/** solving process initialization method of variable pricer (called when branch and bound process is about to begin) */ static SCIP_DECL_PRICERINITSOL(pricerInitsolStp) { SCIP_PRICERDATA* pricerdata; SCIPdebugPrintf("pricerinitsol \n"); assert(scip != NULL); assert(pricer != NULL); pricerdata = SCIPpricerGetData(pricer); assert(pricerdata != NULL); /* allocate memory */ if( !pricerdata->bigt ) { SCIP_CALL( SCIPallocMemoryArray(scip, &(pricerdata->pi), SCIPprobdataGetNEdges(scip) * SCIPprobdataGetRNTerms(scip)) ); } else { SCIP_CALL( SCIPallocMemoryArray(scip, &(pricerdata->pi), SCIPprobdataGetNEdges(scip)) ); } SCIP_CALL( SCIPallocMemoryArray(scip, &(pricerdata->mi), SCIPprobdataGetRNTerms(scip)) ); SCIP_CALL( SCIPallocMemoryArray(scip, &pricerdata->ncreatedvars, SCIPprobdataGetRNTerms(scip)) ); BMSclearMemoryArray(pricerdata->ncreatedvars, SCIPprobdataGetRNTerms(scip)); return SCIP_OKAY; }
/* reads problem from file */ SCIP_RETCODE SCIPreadDec( SCIP* scip, /**< SCIP data structure */ const char* filename, /**< full path and name of file to read, or NULL if stdin should be used */ SCIP_RESULT* result /**< pointer to store the result of the file reading call */ ) { SCIP_READER* reader; DECINPUT decinput; int i; if( SCIPgetStage(scip) < SCIP_STAGE_TRANSFORMED ) SCIP_CALL( SCIPtransformProb(scip) ); reader = SCIPfindReader(scip, READER_NAME); assert(reader != NULL); /* initialize DEC input data */ decinput.file = NULL; decinput.linebuf[0] = '\0'; SCIP_CALL( SCIPallocMemoryArray(scip, &decinput.token, DEC_MAX_LINELEN) ); /*lint !e506*/ decinput.token[0] = '\0'; SCIP_CALL( SCIPallocMemoryArray(scip, &decinput.tokenbuf, DEC_MAX_LINELEN) ); /*lint !e506*/ decinput.tokenbuf[0] = '\0'; for( i = 0; i < DEC_MAX_PUSHEDTOKENS; ++ i ) { SCIP_CALL( SCIPallocMemoryArray(scip, &decinput.pushedtokens[i], DEC_MAX_LINELEN) ); /*lint !e506 !e866*/ } decinput.npushedtokens = 0; decinput.linenumber = 0; decinput.linepos = 0; decinput.section = DEC_START; decinput.presolved = FALSE; decinput.haspresolvesection = FALSE; decinput.nblocks = NOVALUE; decinput.blocknr = - 2; decinput.haserror = FALSE; /* read the file */ SCIP_CALL( readDECFile(scip, reader, &decinput, filename) ); /* free dynamically allocated memory */ SCIPfreeMemoryArray(scip, &decinput.token); SCIPfreeMemoryArray(scip, &decinput.tokenbuf); for( i = 0; i < DEC_MAX_PUSHEDTOKENS; ++ i ) { SCIPfreeMemoryArray(scip, &decinput.pushedtokens[i]); } /* evaluate the result */ if( decinput.haserror ) return SCIP_READERROR; else { *result = SCIP_SUCCESS; } return SCIP_OKAY; }
/* reads problem from file */ SCIP_RETCODE SCIPreadBlk( SCIP* scip, /**< SCIP data structure */ const char* filename, /**< full path and name of file to read, or NULL if stdin should be used */ SCIP_RESULT* result /**< pointer to store the result of the file reading call */ ) { SCIP_READER* reader; BLKINPUT blkinput; int i; reader = SCIPfindReader(scip, READER_NAME); assert(reader != NULL); /* initialize BLK input data */ blkinput.file = NULL; blkinput.linebuf[0] = '\0'; SCIP_CALL( SCIPallocMemoryArray(scip, &blkinput.token, BLK_MAX_LINELEN) ); /*lint !e506*/ blkinput.token[0] = '\0'; SCIP_CALL( SCIPallocMemoryArray(scip, &blkinput.tokenbuf, BLK_MAX_LINELEN) ); /*lint !e506*/ blkinput.tokenbuf[0] = '\0'; for( i = 0; i < BLK_MAX_PUSHEDTOKENS; ++i ) { SCIP_CALL( SCIPallocMemoryArray(scip, &blkinput.pushedtokens[i], BLK_MAX_LINELEN) ); /*lint !e506 !e866*/ } blkinput.npushedtokens = 0; blkinput.linenumber = 0; blkinput.linepos = 0; blkinput.section = BLK_START; blkinput.presolved = FALSE; blkinput.haspresolvesection = FALSE; blkinput.nblocks = -1; blkinput.blocknr = -2; blkinput.haserror = FALSE; /* read the file */ SCIP_CALL( readBLKFile(scip, reader, &blkinput, filename) ); /* free dynamically allocated memory */ SCIPfreeMemoryArray(scip, &blkinput.token); SCIPfreeMemoryArray(scip, &blkinput.tokenbuf); for( i = 0; i < BLK_MAX_PUSHEDTOKENS; ++i ) { SCIPfreeMemoryArray(scip, &blkinput.pushedtokens[i]); } /* evaluate the result */ if( blkinput.haserror ) return SCIP_READERROR; else { *result = SCIP_SUCCESS; } return SCIP_OKAY; }
/** reads problem from file */ SCIP_RETCODE SCIPreadDiff( SCIP* scip, /**< SCIP data structure */ SCIP_READER* reader, /**< the file reader itself */ const char* filename, /**< full path and name of file to read, or NULL if stdin should be used */ SCIP_RESULT* result /**< pointer to store the result of the file reading call */ ) { /*lint --e{715}*/ LPINPUT lpinput; int i; /* initialize LP input data */ lpinput.file = NULL; lpinput.linebuf[0] = '\0'; lpinput.probname[0] = '\0'; lpinput.objname[0] = '\0'; SCIP_CALL( SCIPallocMemoryArray(scip, &lpinput.token, LP_MAX_LINELEN) ); /*lint !e506*/ lpinput.token[0] = '\0'; SCIP_CALL( SCIPallocMemoryArray(scip, &lpinput.tokenbuf, LP_MAX_LINELEN) ); /*lint !e506*/ lpinput.tokenbuf[0] = '\0'; for( i = 0; i < LP_MAX_PUSHEDTOKENS; ++i ) { SCIP_CALL( SCIPallocMemoryArray(scip, &(lpinput.pushedtokens[i]), LP_MAX_LINELEN) ); /*lint !e866 !e506*/ } lpinput.npushedtokens = 0; lpinput.linenumber = 0; lpinput.linepos = 0; lpinput.section = LP_START; lpinput.objsense = SCIP_OBJSENSE_MINIMIZE; lpinput.haserror = FALSE; lpinput.comment = FALSE; lpinput.endline = FALSE; /* read the file */ SCIP_CALL( readDiffFile(scip, &lpinput, filename) ); /* free dynamically allocated memory */ SCIPfreeMemoryArray(scip, &lpinput.token); SCIPfreeMemoryArray(scip, &lpinput.tokenbuf); for( i = 0; i < LP_MAX_PUSHEDTOKENS; ++i ) { SCIPfreeMemoryArray(scip, &lpinput.pushedtokens[i]); } /* evaluate the result */ if( lpinput.haserror ) return SCIP_READERROR; else { /* set objective sense */ SCIP_CALL( SCIPsetObjsense(scip, lpinput.objsense) ); *result = SCIP_SUCCESS; } return SCIP_OKAY; }
/** copies user data of source SCIP for the target SCIP */ static SCIP_DECL_PROBCOPY(probcopyLOP) { int n; int i; int j; assert( scip != NULL ); assert( sourcescip != NULL ); assert( sourcedata != NULL ); assert( targetdata != NULL ); /* set up data */ SCIP_CALL( SCIPallocMemory(scip, targetdata) ); n = sourcedata->n; (*targetdata)->n = n; /* set matrices */ SCIP_CALL( SCIPallocMemoryArray(scip, &((*targetdata)->W), n) ); SCIP_CALL( SCIPallocMemoryArray(scip, &((*targetdata)->vars), n) ); for( i = 0; i < n; ++i ) { SCIP_CALL( SCIPallocMemoryArray(scip, &((*targetdata)->W[i]), n) ); /*lint !e866*/ SCIP_CALL( SCIPallocMemoryArray(scip, &((*targetdata)->vars[i]), n) ); /*lint !e866*/ for( j = 0; j < n; ++j ) { if( i != j ) { SCIP_VAR* var; SCIP_Bool success; SCIP_CALL( SCIPgetTransformedVar(sourcescip, sourcedata->vars[i][j], &var) ); SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, var, &((*targetdata)->vars[i][j]), varmap, consmap, global, &success) ); assert(success); assert((*targetdata)->vars[i][j] != NULL); SCIP_CALL( SCIPcaptureVar(scip, (*targetdata)->vars[i][j]) ); } else (*targetdata)->vars[i][j] = NULL; } } *result = SCIP_SUCCESS; return SCIP_OKAY; }
/** solving process initialization method of constraint handler (called when branch and bound process is about to begin) */ static SCIP_DECL_CONSINITSOL(consInitsolOrigbranch) { /*lint --e{715}*/ SCIP_CONSHDLRDATA* conshdlrData; assert(scip != NULL); assert(conshdlr != NULL); assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0); conshdlrData = SCIPconshdlrGetData(conshdlr); assert(conshdlrData != NULL); /* prepare stack */ SCIP_CALL( SCIPallocMemoryArray(scip, &conshdlrData->stack, conshdlrData->maxstacksize) ); assert( conshdlrData->nstack >= 0 ); /* check consistency */ if( conshdlrData->rootcons != NULL ) { SCIP_CALL( SCIPreleaseCons(scip, &conshdlrData->rootcons) ); conshdlrData->rootcons = NULL; --(conshdlrData->nstack); } GCGconsOrigbranchCheckConsistency(scip); return SCIP_OKAY; }
/** set original variable pointers */ SCIP_RETCODE SCIPconshdlrBenders::setOriginalVariables(int nvars, SCIP_Var ** vars) { nvars_ = nvars; SCIP_CALL(SCIPallocMemoryArray(scip_, &vars_, nvars_)); for (int j = 0; j < nvars_; ++j) vars_[j] = vars[j]; return SCIP_OKAY; }
/** create linear ordering problem model */ SCIP_RETCODE LOPgenerateModel( SCIP* scip /**< SCIP data structure */ ) { SCIP_PROBDATA* probdata; SCIP_CONS* cons; int i, j; /* get problem data */ probdata = SCIPgetProbData(scip); assert( probdata != NULL ); /* generate variables */ SCIP_CALL( SCIPallocMemoryArray(scip, &probdata->vars, probdata->n) ); for (i = 0; i < probdata->n; ++i) { SCIP_CALL( SCIPallocMemoryArray(scip, &(probdata->vars[i]), probdata->n) ); /*lint !e866*/ for (j = 0; j < probdata->n; ++j) { if (j != i) { char s[SCIP_MAXSTRLEN]; (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "x#%d#%d", i, j); SCIP_CALL( SCIPcreateVar(scip, &(probdata->vars[i][j]), s, 0.0, 1.0, probdata->W[i][j], SCIP_VARTYPE_BINARY, TRUE, FALSE, NULL, NULL, NULL, NULL, NULL)); SCIP_CALL( SCIPaddVar(scip, probdata->vars[i][j]) ); } else probdata->vars[i][j] = NULL; } } /* generate linear ordering constraint */ SCIP_CALL( SCIPcreateConsLinearOrdering(scip, &cons, "LOP", probdata->n, probdata->vars, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE)); SCIP_CALL( SCIPaddCons(scip, cons) ); SCIP_CALL( SCIPreleaseCons(scip, &cons) ); /* set maximization */ SCIP_CALL( SCIPsetObjsense(scip, SCIP_OBJSENSE_MAXIMIZE) ); return SCIP_OKAY; }
SCIP_RETCODE SCIPreadLIBSVMPolicy( SCIP* scip, char* fname, SCIP_POLICY** policy ) { int nlines = 0; int i; char buffer[SCIP_MAXSTRLEN]; FILE* file = fopen(fname, "r"); if( file == NULL ) { SCIPerrorMessage("cannot open file <%s> for reading\n", fname); SCIPprintSysError(fname); return SCIP_NOFILE; } /* find out weight vector size */ while( fgets(buffer, (int)sizeof(buffer), file) != NULL ) nlines++; /* don't count libsvm model header */ assert(nlines >= HEADERSIZE_LIBSVM); (*policy)->size = nlines - HEADERSIZE_LIBSVM; fclose(file); if( (*policy)->size == 0 ) { SCIPerrorMessage("empty policy model\n"); return SCIP_NOFILE; } SCIP_CALL( SCIPallocMemoryArray(scip, &(*policy)->weights, (*policy)->size) ); /* have to reopen to read weights */ file = fopen(fname, "r"); /* skip header */ for( i = 0; i < HEADERSIZE_LIBSVM; i++ ) fgets(buffer, (int)sizeof(buffer), file); for( i = 0; i < (*policy)->size; i++ ) fscanf(file, "%"SCIP_REAL_FORMAT, &((*policy)->weights[i])); fclose(file); SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "policy of size %d from file <%s> was %s\n", (*policy)->size, fname, "read, will be used in the dagger node selector"); return SCIP_OKAY; }
/* standard "main" method for mex interface */ void mexFunction( int nlhs, /* number of expected outputs */ mxArray* plhs[], /* array of pointers to output arguments */ int nrhs, /* number of inputs */ const mxArray* prhs[] /* array of pointers to input arguments */ ) { SCIP* scip; SCIP_VAR** vars; SCIP_Real* objs; SCIP_Real* lhss; SCIP_Real* rhss; SCIP_Real* lbs; SCIP_Real* ubs; SCIP_Real* matrix; SCIP_Real* bestsol; SCIP_Real* objval; char* vartypes; char objsense[SCIP_MAXSTRLEN]; int nvars; int nconss; int stringsize; int i; if( SCIPmajorVersion() < 2 ) { mexErrMsgTxt("SCIP versions less than 2.0 are not supported\n"); return; } /* initialize SCIP */ SCIP_CALL_ABORT( SCIPcreate(&scip) ); /* output SCIP information */ SCIPprintVersion(scip, NULL); /* include default SCIP plugins */ SCIP_CALL_ABORT( SCIPincludeDefaultPlugins(scip) ); if( nlhs != 2 || nrhs != 8 ) mexErrMsgTxt("invalid number of parameters. Call as [bestsol, objval] = matscip(matrix, lhs, rhs, obj, lb, ub, vartype, objsense)\n"); if( mxIsSparse(prhs[0]) ) mexErrMsgTxt("sparse matrices are not supported yet"); /* ???????? of course this has to change */ /* get linear constraint coefficient matrix */ matrix = mxGetPr(prhs[0]); if( matrix == NULL ) mexErrMsgTxt("matrix must not be NULL"); if( mxGetNumberOfDimensions(prhs[0]) != 2 ) mexErrMsgTxt("matrix must have exactly two dimensions"); /* get dimensions of matrix */ nconss = mxGetM(prhs[0]); nvars = mxGetN(prhs[0]); assert(nconss > 0); assert(nvars > 0); /* get left hand sides of linear constraints */ lhss = mxGetPr(prhs[1]); if( mxGetM(prhs[1]) != nconss ) mexErrMsgTxt("dimension of left hand side vector does not match matrix dimension"); assert(lhss != NULL); /* get right hand sides of linear constraints */ rhss = mxGetPr(prhs[2]); if( mxGetM(prhs[2]) != nconss ) mexErrMsgTxt("dimension of right hand side vector does not match matrix dimension"); assert(rhss != NULL); /* get objective coefficients */ objs = mxGetPr(prhs[3]); if( mxGetM(prhs[3]) != nvars ) mexErrMsgTxt("dimension of objective coefficient vector does not match matrix dimension"); /* get lower bounds of variables */ lbs = mxGetPr(prhs[4]); if( mxGetM(prhs[4]) != nvars ) mexErrMsgTxt("dimension of lower bound vector does not match matrix dimension"); /* get upper bounds of variables */ ubs = mxGetPr(prhs[5]); if( mxGetM(prhs[5]) != nvars ) mexErrMsgTxt("dimension of upper bound vector does not match matrix dimension"); /* allocate memory for variable type characters */ SCIP_CALL_ABORT( SCIPallocMemoryArray(scip, &vartypes, nvars+1) ); /* get variable types */ if( mxGetString(prhs[6], vartypes, nvars+1) != 0 ) mexErrMsgTxt("Error when parsing variable types, maybe a wrong vector dimension?"); /* get objective sense */ stringsize = mxGetNumberOfElements(prhs[7]); if( stringsize != 3 ) mexErrMsgTxt("objective sense must be a three character word: \"max\" or \"min\""); if( mxGetString(prhs[7], objsense, stringsize+1) != 0) mexErrMsgTxt("Error when parsing objective sense string"); if( strcmp(objsense,"max") != 0 && strcmp(objsense,"min") != 0 ) mexErrMsgTxt("objective sense must be either \"max\" or \"min\""); /* get output parameters */ plhs[0] = mxCreateDoubleMatrix(nvars, 1, mxREAL); bestsol = mxGetPr(plhs[0]); plhs[1] = mxCreateDoubleScalar(mxREAL); objval = mxGetPr(plhs[1]); /* create SCIP problem */ SCIP_CALL_ABORT( SCIPcreateProb(scip, "mex_prob", NULL, NULL, NULL, NULL, NULL, NULL, NULL) ); /* allocate memory for variable array */ SCIP_CALL_ABORT( SCIPallocMemoryArray(scip, &vars, nvars) ); /* create variables */ for( i = 0; i < nvars; ++i) { SCIP_VARTYPE vartype; char varname[SCIP_MAXSTRLEN]; /* convert vartype character to SCIP vartype */ if( vartypes[i] == 'i' ) vartype = SCIP_VARTYPE_INTEGER; else if( vartypes[i] == 'b' ) vartype = SCIP_VARTYPE_BINARY; else if( vartypes[i] == 'c' ) vartype = SCIP_VARTYPE_CONTINUOUS; else mexErrMsgTxt("unkown variable type"); /* variables get canonic names x_i */ (void) SCIPsnprintf(varname, SCIP_MAXSTRLEN, "x_%d", i); /* create variable object and add it to SCIP */ SCIP_CALL_ABORT( SCIPcreateVar(scip, &vars[i], varname, lbs[i], ubs[i], objs[i], vartype, TRUE, FALSE, NULL, NULL, NULL, NULL, NULL) ); assert(vars[i] != NULL); SCIP_CALL_ABORT( SCIPaddVar(scip, vars[i]) ); } /* create linear constraints */ for( i = 0; i < nconss; ++i ) { SCIP_CONS* cons; char consname[SCIP_MAXSTRLEN]; int j; /* constraints get canonic names cons_i */ (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "cons_%d", i); /* create empty linear constraint */ SCIP_CALL_ABORT( SCIPcreateConsLinear(scip, &cons, consname, 0, NULL, NULL, lhss[i], rhss[i], TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) ); /* add non-zero coefficients to linear constraint */ for( j = 0; j < nvars; ++j ) { if( !SCIPisFeasZero(scip, matrix[i+j*nconss]) ) { SCIP_CALL_ABORT( SCIPaddCoefLinear(scip, cons, vars[j], matrix[i+j*nconss]) ); } } /* add constraint to SCIP and release it */ SCIP_CALL_ABORT( SCIPaddCons(scip, cons) ); SCIP_CALL_ABORT( SCIPreleaseCons(scip, &cons) ); } /* set objective sense in SCIP */ if( strcmp(objsense,"max") == 0) { SCIP_CALL_ABORT( SCIPsetObjsense(scip, SCIP_OBJSENSE_MAXIMIZE) ); } else if( strcmp(objsense,"min") == 0) { SCIP_CALL_ABORT( SCIPsetObjsense(scip, SCIP_OBJSENSE_MINIMIZE) ); } else /* this should have been caught earlier when parsing objsense */ mexErrMsgTxt("unkown objective sense"); /* solve SCIP problem */ SCIP_CALL_ABORT( SCIPsolve(scip) ); /* if SCIP found a solution, pass it back into MATLAB output parameters */ if( SCIPgetNSols > 0 ) { SCIP_SOL* scipbestsol; /* get incumbent solution vector */ scipbestsol = SCIPgetBestSol(scip); assert(scipbestsol != NULL); /* get objective value of incumbent solution */ *objval = SCIPgetSolOrigObj(scip, scipbestsol); assert(!SCIPisInfinity(scip, REALABS(*objval))); /* copy solution values into output vector */ for( i = 0; i < nvars; ++i ) bestsol[i] = SCIPgetSolVal(scip,scipbestsol,vars[i]); } /* release variables */ for( i = 0; i < nvars; ++i ) { SCIP_CALL_ABORT( SCIPreleaseVar(scip, &vars[i]) ); } /* free memory for variable arrays */ SCIPfreeMemoryArray(scip, &vartypes); SCIPfreeMemoryArray(scip, &vars); /* deinitialize SCIP */ SCIP_CALL_ABORT( SCIPfree(&scip) ); /* check for memory leaks */ BMScheckEmptyMemory(); return; }
/** read LP in "COL File Format" */ static SCIP_RETCODE readCol( SCIP* scip, /**< SCIP data structure */ const char* filename /**< name of the input file */ ) { SCIP_FILE* fp; /* file-reader */ char buf[COL_MAX_LINELEN]; /* maximal length of line */ int nedges; int nnodes; int line_nr; char* char_p; char* probname; int** edges; int i; int j; int begin; int end; int nduplicateedges; SCIP_Bool duplicateedge; assert(scip != NULL); assert(filename != NULL); if (NULL == (fp = SCIPfopen(filename, "r"))) { SCIPerrorMessage("cannot open file <%s> for reading\n", filename); perror(filename); return SCIP_NOFILE; } /* Get problem name from filename and save it */ SCIPfgets(buf, sizeof(buf), fp); i = 1; while ( (filename[i] != '/') && (filename[i] != '\0') ) { i++; } if ( filename[i] != '/' ) { j = i; i = -1; } else { j = i+1; while ( filename[i] == '/' && filename[j] != '\0' ) { j = i+1; while ( filename[j] != '\0' ) { j++; if ( filename[j] == '/' ) { i = j; break; } } } } SCIPallocMemoryArray(scip, &probname, j-i-4); strncpy(probname, &filename[i+1], j-i-5); probname[j-i-5]= '\0'; /* Read until information about graph starts */ line_nr = 0; while( !SCIPfeof(fp) && (buf[0] != 'p') ) { SCIPfgets(buf, sizeof(buf), fp); line_nr++; } /* no graph information in file! */ if ( SCIPfeof(fp) ) { SCIPerrorMessage("Error! Could not find line starting with 'p'.\n"); return SCIP_READERROR; } /* wrong format of the line containig number of nodes and edges */ if ( buf[2] != 'e' || buf[3] != 'd' || buf[4] != 'g' || buf[5] != 'e' ) { SCIPerrorMessage("Line starting with 'p' must continue with 'edge'!\n"); return SCIP_READERROR; } char_p = &buf[6]; /* if line reads 'edges' (non-standard!), instead of 'edge'. */ if ( *char_p == 's' ) ++(char_p); /* read out number of nodes and edges, the pointer char_p will be changed */ nduplicateedges = 0; nnodes = getNextNumber(&char_p); nedges = getNextNumber(&char_p); if ( nnodes <= 0 ) { SCIPerrorMessage("Number of vertices must be positive!\n"); return SCIP_READERROR; } if ( nedges < 0 ) { SCIPerrorMessage("Number of edges must be nonnegative!\n"); return SCIP_READERROR; } /* create array for edges */ SCIP_CALL( SCIPallocMemoryArray(scip, &edges, nedges) ); for( i = 0; i < nedges; i++) { SCIP_CALL( SCIPallocMemoryArray(scip, &(edges[i]), 2) ); } /* fill array for edges */ i = 0; while ( !SCIPfeof(fp) ) { SCIPfgets(buf, sizeof(buf), fp); line_nr++; if ( buf[0] == 'e') { duplicateedge = FALSE; char_p = &buf[2]; begin = getNextNumber(&char_p); end = getNextNumber(&char_p); for ( j = 0; j < i; j++) { if ( ((edges[j][0] == begin) && (edges[j][1] == end)) || ((edges[j][1] == begin) && (edges[j][0] == end)) ) { duplicateedge = TRUE; nduplicateedges++; break; } } if ( !duplicateedge ) { if( i >= nedges ) { SCIPerrorMessage("more edges than expected: expected %d many, but got already %d'th (non-duplicate) edge", nedges, i+1); return SCIP_READERROR; } edges[i][0] = begin; edges[i][1] = end; assert((edges[i][0] > 0) && (edges[i][0] <= nnodes)); assert((edges[i][1] > 0) && (edges[i][1] <= nnodes)); i++; } } } if( i + nduplicateedges != nedges ) { SCIPerrorMessage("incorrect number of edges: expected %d many, but got %d many\n", nedges, i + nduplicateedges); return SCIP_ERROR; } printf("Read graph: %d nodes, %d edges (%d duplicates)\n", nnodes, nedges, nduplicateedges); /* create problem data */ SCIP_CALL( SCIPcreateProbColoring(scip, probname, nnodes, nedges-nduplicateedges, edges) ); /* create LP */ SCIPdebugMessage("Erstelle LP...\n"); COLORprobSetUpArrayOfCons(scip); /* activate the pricer */ SCIP_CALL( SCIPactivatePricer(scip, SCIPfindPricer(scip, "coloring")) ); SCIP_CALL( SCIPsetObjIntegral(scip) ); for ( i = nedges-1; i >= 0; i--) { SCIPfreeMemoryArray(scip, &(edges[i])); } SCIPfreeMemoryArray(scip, &edges); SCIPfreeMemoryArray(scip, &probname); SCIPfclose(fp); return SCIP_OKAY; }
/** reads an BLK file */ static SCIP_RETCODE readBLKFile( SCIP* scip, /**< SCIP data structure */ SCIP_READER* reader, /**< reader data structure */ BLKINPUT* blkinput, /**< BLK reading data */ const char* filename /**< name of the input file */ ) { DEC_DECOMP *decdecomp; int i; int nconss; int nblocksread; int nvars; SCIP_READERDATA* readerdata; SCIP_CONS** conss; nblocksread = FALSE; assert(scip != NULL); assert(reader != NULL); assert(blkinput != NULL); if( SCIPgetStage(scip) < SCIP_STAGE_TRANSFORMED ) SCIP_CALL( SCIPtransformProb(scip) ); readerdata = SCIPreaderGetData(reader); assert(readerdata != NULL); readerdata->nlinkingcons = SCIPgetNConss(scip); readerdata->nlinkingvars = 0; nvars = SCIPgetNVars(scip); conss = SCIPgetConss(scip); nconss = SCIPgetNConss(scip); /* alloc: var -> block mapping */ SCIP_CALL( SCIPallocMemoryArray(scip, &readerdata->varstoblock, nvars) ); for( i = 0; i < nvars; i ++ ) { readerdata->varstoblock[i] = NOVALUE; } /* alloc: linkingvar -> blocks mapping */ SCIP_CALL( SCIPallocMemoryArray(scip, &readerdata->linkingvarsblocks, nvars) ); SCIP_CALL( SCIPallocMemoryArray(scip, &readerdata->nlinkingvarsblocks, nvars) ); BMSclearMemoryArray(readerdata->linkingvarsblocks, nvars); BMSclearMemoryArray(readerdata->nlinkingvarsblocks, nvars); /* cons -> block mapping */ SCIP_CALL( SCIPhashmapCreate(&readerdata->constoblock, SCIPblkmem(scip), nconss) ); for( i = 0; i < SCIPgetNConss(scip); i ++ ) { SCIP_CALL( SCIPhashmapInsert(readerdata->constoblock, conss[i], (void*)(size_t) NOVALUE) ); } /* open file */ blkinput->file = SCIPfopen(filename, "r"); if( blkinput->file == NULL ) { SCIPerrorMessage("cannot open file <%s> for reading\n", filename); SCIPprintSysError(filename); return SCIP_NOFILE; } /* parse the file */ blkinput->section = BLK_START; while( blkinput->section != BLK_END && !hasError(blkinput) ) { switch( blkinput->section ) { case BLK_START: SCIP_CALL( readStart(scip, blkinput) ); break; case BLK_PRESOLVED: SCIP_CALL( readPresolved(scip, blkinput) ); if( blkinput->presolved && SCIPgetStage(scip) < SCIP_STAGE_PRESOLVED ) { assert(blkinput->haspresolvesection); /** @bug GCG should be able to presolve the problem first */ SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "decomposition belongs to the presolved problem, please presolve the problem first.\n"); goto TERMINATE; } break; case BLK_NBLOCKS: SCIP_CALL( readNBlocks(scip, blkinput) ); if( blkinput->haspresolvesection && !blkinput->presolved && SCIPgetStage(scip) >= SCIP_STAGE_PRESOLVED ) { SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "decomposition belongs to the unpresolved problem, please re-read the problem and read the decomposition without presolving.\n"); goto TERMINATE; } if( !blkinput->haspresolvesection ) { SCIPwarningMessage(scip, "decomposition has no presolve section at beginning. The behaviour is undefined. See the FAQ for further information.\n"); } break; case BLK_BLOCK: if( nblocksread == FALSE ) { /* alloc n vars per block */ SCIP_CALL( SCIPallocMemoryArray(scip, &readerdata->nblockvars, blkinput->nblocks) ); SCIP_CALL( SCIPallocMemoryArray(scip, &readerdata->nblockcons, blkinput->nblocks) ); SCIP_CALL( SCIPallocMemoryArray(scip, &readerdata->blockcons, blkinput->nblocks) ); for( i = 0; i < blkinput->nblocks; ++i ) { readerdata->nblockvars[i] = 0; readerdata->nblockcons[i] = 0; SCIP_CALL( SCIPallocMemoryArray(scip, &(readerdata->blockcons[i]), nconss) ); /*lint !e866*/ } nblocksread = TRUE; } SCIP_CALL( readBlock(scip, blkinput, readerdata) ); break; case BLK_MASTERCONSS: SCIP_CALL( readMasterconss(scip, blkinput, readerdata) ); break; case BLK_END: /* this is already handled in the while() loop */ default: SCIPerrorMessage("invalid BLK file section <%d>\n", blkinput->section); return SCIP_INVALIDDATA; } } SCIP_CALL( DECdecompCreate(scip, &decdecomp) ); /* fill decomp */ SCIP_CALL( fillDecompStruct(scip, blkinput, decdecomp, readerdata) ); /* add decomp to cons_decomp */ SCIP_CALL( SCIPconshdlrDecompAddDecdecomp(scip, decdecomp) ); for( i = 0; i < nvars; ++i ) { assert(readerdata->linkingvarsblocks[i] != NULL || readerdata->nlinkingvarsblocks[i] == 0); if( readerdata->nlinkingvarsblocks[i] > 0 ) { SCIPfreeMemoryArray(scip, &readerdata->linkingvarsblocks[i]); } } TERMINATE: if( nblocksread ) { for( i = blkinput->nblocks - 1; i >= 0; --i ) { SCIPfreeMemoryArray(scip, &(readerdata->blockcons[i])); } SCIPfreeMemoryArray(scip, &readerdata->blockcons); SCIPfreeMemoryArray(scip, &readerdata->nblockcons); SCIPfreeMemoryArray(scip, &readerdata->nblockvars); } SCIPhashmapFree(&readerdata->constoblock); SCIPfreeMemoryArray(scip, &readerdata->nlinkingvarsblocks); SCIPfreeMemoryArray(scip, &readerdata->linkingvarsblocks); SCIPfreeMemoryArray(scip, &readerdata->varstoblock); /* close file */ SCIPfclose(blkinput->file); return SCIP_OKAY; }
/** fills the whole Decomp struct after the blk file has been read */ static SCIP_RETCODE fillDecompStruct( SCIP* scip, /**< SCIP data structure */ BLKINPUT* blkinput, /**< blk reading data */ DEC_DECOMP* decomp, /**< DEC_DECOMP structure to fill */ SCIP_READERDATA* readerdata /**< reader data*/ ) { SCIP_HASHMAP* constoblock; SCIP_CONS** allcons; SCIP_VAR** consvars; int i; int j; int nvars; int blocknr; int nconss; int nblocks; SCIP_Bool valid; assert(scip != NULL); assert(blkinput != NULL); assert(readerdata != NULL); allcons = SCIPgetConss(scip); nvars = SCIPgetNVars(scip); nconss = SCIPgetNConss(scip); nblocks = blkinput->nblocks; DECdecompSetPresolved(decomp, blkinput->presolved); DECdecompSetNBlocks(decomp, nblocks); DECdecompSetDetector(decomp, NULL); DECdecompSetType(decomp, DEC_DECTYPE_ARROWHEAD, &valid); assert(valid); /* hashmaps */ SCIP_CALL( SCIPhashmapCreate(&constoblock, SCIPblkmem(scip), nconss) ); SCIP_CALL( SCIPallocMemoryArray(scip, &consvars, nvars) ); /* assign constraints to blocks or declare them linking */ for( i = 0; i < nconss; i ++ ) { SCIP_CONS* cons; cons = allcons[i]; if( SCIPhashmapGetImage(readerdata->constoblock, cons) == (void*) (size_t) LINKINGVALUE ) { SCIP_CALL( SCIPhashmapInsert(constoblock, cons, (void*) (size_t) (nblocks+1)) ); SCIPdebugMessage("cons %s is linking\n", SCIPconsGetName(cons)); } /* check whether all variables in the constraint belong to one block */ else { int nconsvars; nconsvars = SCIPgetNVarsXXX(scip, cons); assert(nconsvars < nvars); SCIP_CALL( SCIPgetVarsXXX(scip, cons, consvars, nvars) ); blocknr = -1; /* find the first unique assignment of a contained variable to a block */ for( j = 0; j < nconsvars; ++j ) { /* if a contained variables is directly transferred to the master, the constraint is a linking constraint */ if( readerdata->varstoblock[SCIPvarGetProbindex(consvars[j])] == NOVALUE ) { blocknr = -1; break; } /* assign the constraint temporarily to the block of the variable, if it is unique */ if( blocknr == -1 && readerdata->varstoblock[SCIPvarGetProbindex(consvars[j])] != LINKINGVALUE ) { blocknr = readerdata->varstoblock[SCIPvarGetProbindex(consvars[j])]; } } if( blocknr != -1 ) { int varidx; int varblock; /* check whether all contained variables are copied into the assigned block; * if not, the constraint is treated as a linking constraint */ for( j = 0; j < nconsvars; ++j ) { varidx = SCIPvarGetProbindex(consvars[j]); varblock = readerdata->varstoblock[varidx]; assert(varblock != NOVALUE); if( varblock != LINKINGVALUE && varblock != blocknr ) { blocknr = -1; break; } else if( varblock == LINKINGVALUE ) { int k; for( k = 0; k < readerdata->nlinkingvarsblocks[varidx]; ++k ) { if( readerdata->linkingvarsblocks[varidx][k] == blocknr ) break; } /* we did not break, so the variable is not assigned to the block */ if( k == readerdata->nlinkingvarsblocks[varidx] ) { blocknr = -1; break; } } } } if( blocknr == -1 ) { SCIP_CALL( SCIPhashmapInsert(constoblock, cons, (void*) (size_t) (nblocks+1)) ); SCIPdebugMessage("constraint <%s> is a linking constraint\n", SCIPconsGetName(cons)); } else { SCIP_CALL( SCIPhashmapInsert(constoblock, cons, (void*) (size_t) (blocknr+1)) ); SCIPdebugMessage("constraint <%s> is assigned to block %d\n", SCIPconsGetName(cons), blocknr); } } } SCIP_CALL( DECfilloutDecdecompFromConstoblock(scip, decomp, constoblock, nblocks, SCIPgetVars(scip), SCIPgetNVars(scip), SCIPgetConss(scip), SCIPgetNConss(scip), FALSE) ); SCIPfreeMemoryArray(scip, &consvars); return SCIP_OKAY; }
/** reads a block section */ static SCIP_RETCODE readBlock( SCIP* scip, /**< SCIP data structure */ BLKINPUT* blkinput, /**< BLK reading data */ SCIP_READERDATA* readerdata /**< reader data */ ) { int blockid; assert(blkinput != NULL); blockid = blkinput->blocknr; while( getNextToken(blkinput) ) { SCIP_VAR* var; int varidx; int oldblock; /* check if we reached a new section */ if( isNewSection(scip, blkinput) ) return SCIP_OKAY; /* the token must be the name of an existing variable */ var = SCIPfindVar(scip, blkinput->token); if( var == NULL ) { syntaxError(scip, blkinput, "unknown variable in block section"); return SCIP_OKAY; } varidx = SCIPvarGetProbindex(var); oldblock = readerdata->varstoblock[varidx]; /* set the block number of the variable to the number of the current block */ if( oldblock == NOVALUE ) { SCIPdebugMessage("\tVar %s temporary in block %d.\n", SCIPvarGetName(var), blockid); readerdata->varstoblock[varidx] = blockid; ++(readerdata->nblockvars[blockid]); } /* variable was assigned to another (non-linking) block before, so it becomes a linking variable, now */ else if( (oldblock != LINKINGVALUE) ) { assert(oldblock != blockid); SCIPdebugMessage("\tVar %s is linking (old %d != %d new).\n", SCIPvarGetName(var), oldblock, blockid); readerdata->varstoblock[varidx] = LINKINGVALUE; /* decrease the number of variables in the old block and increase the number of linking variables */ --(readerdata->nblockvars[oldblock]); ++(readerdata->nlinkingvars); assert(readerdata->nlinkingvarsblocks[varidx] == 0); assert(readerdata->linkingvarsblocks[varidx] == NULL); SCIP_CALL( SCIPallocMemoryArray(scip, &readerdata->linkingvarsblocks[varidx], 2) ); /*lint !e506 !e866*/ readerdata->linkingvarsblocks[varidx][0] = oldblock; readerdata->linkingvarsblocks[varidx][1] = blockid; readerdata->nlinkingvarsblocks[varidx] = 2; } /* variable is a linking variable already, store the new block to which it belongs */ else { assert(oldblock == LINKINGVALUE); assert(readerdata->nlinkingvarsblocks[varidx] >= 2); assert(readerdata->linkingvarsblocks[varidx] != NULL); SCIP_CALL( SCIPreallocMemoryArray(scip, &readerdata->linkingvarsblocks[varidx], readerdata->nlinkingvarsblocks[varidx] + 1) ); /*lint !e866*/ readerdata->linkingvarsblocks[varidx][readerdata->nlinkingvarsblocks[varidx]] = blockid; ++(readerdata->nlinkingvarsblocks[varidx]); } } return SCIP_OKAY; }
/** transforms the problem */ static SCIP_DECL_PROBTRANS(probtransColoring) { int i; int j; int* firstedge; int* lastedge; assert(scip != NULL); assert(sourcedata != NULL); assert(targetdata != NULL); /* allocate memory */ SCIP_CALL( SCIPallocMemory(scip, targetdata) ); if( !tcliqueCreate(&((*targetdata)->graph)) ) /* create the transformed graph */ { SCIPerrorMessage("could not create the clique graph\n"); return SCIP_ERROR; } (*targetdata)->maxstablesets = sourcedata->maxstablesets; /* copy length of array sets */ (*targetdata)->nstablesets = sourcedata->nstablesets; /* copy number of sets saved in array sets */ (*targetdata)->oldgraph = sourcedata->oldgraph; /* copy link to original graph */ /* allocate memory for sets and lenghts of the sets */ SCIP_CALL( SCIPallocMemoryArray(scip, &((*targetdata)->stablesets), sourcedata->maxstablesets) ); SCIP_CALL( SCIPallocMemoryArray(scip, &((*targetdata)->stablesetlengths), sourcedata->maxstablesets) ); SCIP_CALL( SCIPallocMemoryArray(scip, &((*targetdata)->stablesetvars), sourcedata->maxstablesets) ); SCIP_CALL( SCIPallocMemoryArray(scip, &((*targetdata)->deletednodes), tcliqueGetNNodes(sourcedata->oldgraph)) ); SCIP_CALL( SCIPallocMemoryArray(scip, &((*targetdata)->new2oldnode), tcliqueGetNNodes(sourcedata->oldgraph)) ); for ( i = 0; i < tcliqueGetNNodes(sourcedata->oldgraph); i++ ) { (*targetdata)->deletednodes[i] = sourcedata->deletednodes[i]; (*targetdata)->new2oldnode[i] = sourcedata->new2oldnode[i]; } /* copy stablesetlengths and stablesets */ for ( i = 0; i < sourcedata->nstablesets; i++ ) { assert(sourcedata->stablesetvars[i] != NULL); (*targetdata)->stablesetlengths[i] = sourcedata->stablesetlengths[i]; SCIP_CALL( SCIPtransformVar(scip, sourcedata->stablesetvars[i], &((*targetdata)->stablesetvars[i])) ); SCIP_CALL( SCIPallocBlockMemoryArray(scip, &((*targetdata)->stablesets[i]), sourcedata->stablesetlengths[i]) ); /*lint !e866*/ for ( j = 0; j <sourcedata->stablesetlengths[i]; j++ ) { (*targetdata)->stablesets[i][j] = sourcedata->stablesets[i][j]; } } /* create array for constraints */ SCIP_CALL( SCIPallocMemoryArray(scip, &(*targetdata)->constraints, tcliqueGetNNodes(sourcedata->graph)) ); /* tranform constraints */ SCIP_CALL( SCIPtransformConss(scip, tcliqueGetNNodes(sourcedata->graph), sourcedata->constraints, (*targetdata)->constraints) ); /* copy the graph */ if( !tcliqueAddNode((*targetdata)->graph, tcliqueGetNNodes(sourcedata->graph)-1, 0) ) { SCIPerrorMessage("could not add a node to the clique graph\n"); return SCIP_ERROR; } for ( i = 0; i < tcliqueGetNNodes(sourcedata->graph); i++ ) { /* get adjacent nodes for node i */ firstedge = tcliqueGetFirstAdjedge(sourcedata->graph, i); lastedge = tcliqueGetLastAdjedge(sourcedata->graph, i); while ( firstedge <= lastedge ) { if ( *firstedge > i ) { if( !tcliqueAddEdge((*targetdata)->graph, i, *firstedge) ) { SCIPerrorMessage("could not add an edge to the clique graph\n"); return SCIP_ERROR; } } firstedge++; } } if( !tcliqueFlush((*targetdata)->graph) ) { SCIPerrorMessage("could not flush the clique graph\n"); return SCIP_ERROR; } return SCIP_OKAY; }
/** sets up the problem data */ SCIP_RETCODE SCIPcreateProbColoring( SCIP* scip, /**< SCIP data structure */ const char* name, /**< problem name */ int nnodes, /**< number of nodes */ int nedges, /**< number of edges */ int** edges /**< array with start- and endpoints of the edges */ ) { int i; SCIP_PROBDATA* probdata = NULL; assert(nnodes > 0); /* at least one node */ assert(nedges >= 0); /* no negative number of edges */ printf("Creating problem: %s \n", name); /* allocate memory */ SCIP_CALL( SCIPallocMemory(scip, &probdata) ); /* create graph */ if( !tcliqueCreate(&((probdata)->oldgraph)) ) { SCIPerrorMessage("could not create the clique graph\n"); return SCIP_ERROR; } /* add all nodes from 0 to nnodes-1 */ if( !tcliqueAddNode((probdata)->oldgraph, nnodes-1, 0) ) { SCIPerrorMessage("could not add a node to the clique graph\n"); return SCIP_ERROR; } /* add all edges, first into cache, then flush to add all of them to the graph */ for ( i = 0; i < nedges; i++ ) { assert((edges[i][0] > 0) && (edges[i][0] <= nnodes)); assert((edges[i][1] > 0) && (edges[i][1] <= nnodes)); if( !tcliqueAddEdge((probdata)->oldgraph, edges[i][0]-1, edges[i][1]-1) ) { SCIPerrorMessage("could not add an edge to the clique graph\n"); return SCIP_ERROR; } } if( !tcliqueFlush((probdata)->oldgraph) ) { SCIPerrorMessage("could not flush the clique graph\n"); return SCIP_ERROR; } /* create constraints */ SCIP_CALL( SCIPallocMemoryArray(scip, &(probdata->constraints), nnodes) ); /* at the beginning memory for 2 sets */ SCIP_CALL( SCIPallocMemoryArray(scip, &(probdata->stablesets), 2) ); SCIP_CALL( SCIPallocMemoryArray(scip, &(probdata->stablesetlengths), 2) ); SCIP_CALL( SCIPallocMemoryArray(scip, &(probdata->stablesetvars), 2) ); probdata->maxstablesets = 2; probdata->nstablesets = 0; /* include variable deleted event handler into SCIP */ SCIP_CALL( SCIPincludeEventhdlrBasic(scip, NULL, EVENTHDLR_NAME, EVENTHDLR_DESC, eventExecProbdatavardeleted, NULL) ); /* create problem in SCIP */ SCIP_CALL( SCIPcreateProb(scip, name, probdelorigColoring, probtransColoring, probdeltransColoring, NULL, NULL, NULL, probdata) ); SCIP_CALL( preprocessGraph(scip) ); return SCIP_OKAY; }
/** read weight matrix from file (in LOLIB format) * * Format: * comment line * # of elements * weight matrix (doubles) */ static SCIP_RETCODE LOPreadFile( SCIP* scip, /**< SCIP data structure */ const char* filename, /**< name of file to read */ SCIP_PROBDATA* probdata /**< problem data to be filled */ ) { int i, j; FILE *file; int status; int n; SCIP_Real** W; char s[SCIP_MAXSTRLEN]; /* open file */ file = fopen(filename, "r"); if ( file == NULL ) { SCIPerrorMessage("Could not open file <%s>.\n", filename); return SCIP_NOFILE; } /* skip one line */ if ( fgets(s, SCIP_MAXSTRLEN, file) == NULL ) { SCIPerrorMessage("Error reading file <%s>.\n", filename); return SCIP_READERROR; } /* read number of elements */ status = fscanf(file, "%d", &n); if ( ! status ) { SCIPerrorMessage("Reading failed.\n"); return SCIP_READERROR; } assert( 0 < n ); SCIPinfoMessage(scip, NULL, "Number of elements:\t%d\n\n", n); probdata->n = n; /* set up matrix */ SCIP_CALL( SCIPallocMemoryArray(scip, &W, n) ); for (i = 0; i < n; ++i) SCIP_CALL( SCIPallocMemoryArray(scip, &(W[i]), n) ); /*lint !e866*/ probdata->W = W; /* read matrix */ for (i = 0; i < n; ++i) { for (j = 0; j < n; ++j) { SCIP_Real val; status = fscanf(file, "%lf", &val); if ( ! status ) { SCIPerrorMessage("Reading failed.\n"); return SCIP_READERROR; } W[i][j] = val; } } fclose( file ); return SCIP_OKAY; }
/** reads the blocks section */ static SCIP_RETCODE readBlock( SCIP* scip, /**< SCIP data structure */ DECINPUT* decinput, /**< DEC reading data */ SCIP_READERDATA* readerdata /**< reader data */ ) { int oldblock; int varidx; int consindex; int i; int blockid; int nvars; SCIP_CONS* cons; SCIP_VAR** vars; SCIP_Bool conshasvar; assert(decinput != NULL); assert(readerdata != NULL); while( getNextToken(decinput) ) { /* check if we reached a new section */ if( isNewSection(scip, decinput) ) break; /* the token must be the name of an existing cons */ cons = SCIPfindCons(scip, decinput->token); if( cons == NULL ) { syntaxError(scip, decinput, "unknown constraint in block section"); break; } conshasvar = FALSE; /* get all vars for the specific constraint */ nvars = SCIPgetNVarsXXX(scip, cons); vars = NULL; if( nvars > 0 ) { SCIP_CALL( SCIPallocMemoryArray(scip, &vars, nvars) ); SCIP_CALL( SCIPgetVarsXXX(scip, cons, vars, nvars) ); } blockid = decinput->blocknr; for( i = 0; i < nvars; i ++ ) { SCIP_VAR* var; assert(vars != NULL); /* for flexelint */ if( decinput->presolved ) { var = SCIPvarGetProbvar(vars[i]); if( !SCIPisVarRelevant(var) ) continue; } else var = vars[i]; conshasvar = TRUE; /* store for each var whether it is in none, one or more blocks */ varidx = SCIPvarGetProbindex(var); assert(varidx >= 0 && varidx < SCIPgetNVars(scip)); oldblock = readerdata->varstoblock[varidx]; assert(oldblock == NOVALUE || oldblock == LINKINGVALUE || (oldblock >= 0 && oldblock < decinput->nblocks)); /* variable was assigned to no block before, just assign it to the new block */ if( oldblock == NOVALUE ) { SCIPdebugMessage("\tVar %s temporary in block %d.\n", SCIPvarGetName(vars[i]), blockid); readerdata->varstoblock[varidx] = blockid; ++(readerdata->nblockvars[blockid]); } /* variable was assigned to another (non-linking) block before, so it becomes a linking variable, now */ else if( (oldblock != LINKINGVALUE) && oldblock != blockid ) { SCIPdebugMessage("\tVar %s is linking (old %d != %d new).\n", SCIPvarGetName(vars[i]), oldblock, blockid); assert(oldblock != blockid); readerdata->varstoblock[varidx] = LINKINGVALUE; /* decrease the value again if it is a linking var */ --(readerdata->nblockvars[oldblock]); ++(readerdata->nlinkingvars); } } SCIPfreeMemoryArrayNull(scip, &vars); if( !conshasvar ) { assert(!SCIPhashmapExists(readerdata->constoblock, cons)); SCIPwarningMessage(scip, "Cons <%s> has been deleted by presolving, skipping.\n", SCIPconsGetName(cons)); continue; } /* * saving block <-> constraint */ /** @todo check if linking constraints are not in the subscipcons */ consindex = readerdata->nblockconss[blockid]; readerdata->blockconss[blockid][consindex] = cons; ++(readerdata->nblockconss[blockid]); assert(SCIPhashmapGetImage(readerdata->constoblock, cons) == (void*)(size_t) LINKINGVALUE); SCIPdebugMessage("cons %s is in block %d\n", SCIPconsGetName(cons), blockid); SCIP_CALL( SCIPhashmapSetImage(readerdata->constoblock, cons, (void*) ((size_t) blockid)) ); --(readerdata->nlinkingconss); } return SCIP_OKAY; }
/** * Preprocessing of the graph, using 2 methods in order to find redundant nodes * that can be deleted and easily colored later. * * Foundation of these methods is the computation of a maximum clique C with M nodes. * After this computation, the following two steps are repeated until no node was deleted * in the last iteration: * * 1: Low-Degree: * Iterativly delete all nodes v in the graph G with degree d(v) < M ( don't delete nodes of C ) * * 2: Dominated Neighbourhood: * If the neighbourhood of one node v is part of the neighbourhood of another node w, v can * be deleted, since it can later get the same color as w. */ static SCIP_RETCODE preprocessGraph( SCIP* scip /**< SCIP data structure */ ) { SCIP_PROBDATA* probdata; /* the problemdata */ SCIP_Bool changed; /* was the graph changed in the last round of preprocessing? */ SCIP_Bool dominates; /* is the neighbourhood of one node dominated by the neigbourhood of another one?*/ int* maxcliquenodes; /* pointer to store nodes of the maximum weight clique */ int nmaxcliquenodes; /* number of nodes in the maximum weight clique */ TCLIQUE_WEIGHT maxcliqueweight; /* weight of the maximum weight clique */ TCLIQUE_STATUS status; /* status of clique-computation */ TCLIQUE_GRAPH* currgraph; /* the current, not preprocessed graph in each step */ int currnnodes; /* the current number of nodes in each step */ int actnewnode; /* the number of nodes yet marked for beeing in the graph in the next round */ int* newnodes; /* the nodes that will be in the graph in the next round */ int* degrees; /* the degrees of the nodes */ int myround; /* the number of the current round */ int ndeletednodes; /* the total number of deleted nodes */ int nnodesdeleteddegreethisround; /* the number of nodes deleted due to low degree in the current round */ int nnodesdeletedneighbourthisround; /* the number of nodes deleted due to neighbourhood in the current round */ int* firstedge; /* pointer for the edges in the graph */ int* lastedge; /* pointer for the edges in the graph */ int i; int j; char opt; assert(scip != NULL); probdata = SCIPgetProbData(scip); assert(probdata != NULL); printf("\npreprocessing...\n"); /* copy the old graph */ if( !tcliqueCreate(&currgraph) ) { SCIPerrorMessage("could not flush the clique graph\n"); return SCIP_ERROR; } assert(currgraph != NULL); if( !tcliqueAddNode(currgraph, tcliqueGetNNodes(probdata->oldgraph)-1, 0) ) { SCIPerrorMessage("could not add a node to the clique graph\n"); return SCIP_ERROR; } for ( i = 0; i < tcliqueGetNNodes(probdata->oldgraph); i++ ) { /* get adjacent nodes for node i */ firstedge = tcliqueGetFirstAdjedge(probdata->oldgraph, i); lastedge = tcliqueGetLastAdjedge(probdata->oldgraph, i); while ( firstedge <= lastedge ) { if ( *firstedge > i ) { if( !tcliqueAddEdge(currgraph, i, *firstedge) ) { SCIPerrorMessage("could not add an edge to the clique graph\n"); return SCIP_ERROR; } } firstedge++; } } if( !tcliqueFlush(currgraph) ) { SCIPerrorMessage("could not flush the clique graph\n"); return SCIP_ERROR; } currnnodes = tcliqueGetNNodes(probdata->oldgraph); /* get memory for array of deletednodes */ SCIP_CALL( SCIPallocMemoryArray(scip, &(probdata->deletednodes), COLORprobGetOriginalNNodes(scip)) ); /* get memory for array new2oldnodes */ SCIP_CALL( SCIPallocMemoryArray(scip, &(probdata->new2oldnode), COLORprobGetOriginalNNodes(scip)) ); SCIP_CALL( SCIPallocBufferArray(scip, &newnodes, COLORprobGetOriginalNNodes(scip)) ); SCIP_CALL( SCIPallocBufferArray(scip, &maxcliquenodes, COLORprobGetOriginalNNodes(scip)) ); for ( i = 0; i < currnnodes; i++ ) { /* set weights of the nodes to 1 */ tcliqueChangeWeight(currgraph, i, 1); /* every node in the graph represents the same node in the original graph */ probdata->new2oldnode[i] = i; } /* compute maximum clique */ tcliqueMaxClique(NULL, NULL, NULL, NULL, currgraph, NULL, NULL, maxcliquenodes, &nmaxcliquenodes, &maxcliqueweight, 0, 0, 50000, 0, INT_MAX, -1, NULL, &status); opt = ( status == TCLIQUE_OPTIMAL ? ' ' : '*' ); printf("size of the maximum clique: %d%c \n", nmaxcliquenodes, opt); ndeletednodes = 0; nnodesdeleteddegreethisround = 1; nnodesdeletedneighbourthisround = 1; myround = 0; /* main loop */ while ( (nnodesdeleteddegreethisround > 0) || (nnodesdeletedneighbourthisround > 0) ) { myround++; nnodesdeleteddegreethisround = 0; nnodesdeletedneighbourthisround = 0; changed = TRUE; /* node degree deletion loop */ while ( changed == TRUE ) { changed = FALSE; actnewnode = 0; degrees = tcliqueGetDegrees(currgraph); for (i = 0; i < currnnodes; i++) { /* degree is low, node can be deleted */ if ( (degrees[i] < nmaxcliquenodes ) && (!COLORprobIsNodeInArray(probdata->new2oldnode[i], maxcliquenodes, nmaxcliquenodes)) ) { probdata->deletednodes[ndeletednodes] = probdata->new2oldnode[i]; changed = TRUE; nnodesdeleteddegreethisround++; ndeletednodes++; } /* node will be in the new graph, because degree is not low enought for deletion or it is in the maxClique */ else { newnodes[actnewnode] = probdata->new2oldnode[i]; actnewnode++; } } /* at least one node was deletet, create new graph ( tclique doesn't support deletion of nodes) */ if ( changed ) { assert(actnewnode+ndeletednodes == COLORprobGetOriginalNNodes(scip)); /* create new current graph */ tcliqueFree(&currgraph); if( !tcliqueCreate(&currgraph) ) { SCIPerrorMessage("could not create the clique graph\n"); return SCIP_ERROR; } assert(currgraph != NULL); if( !tcliqueAddNode(currgraph, actnewnode-1, 0) ) { SCIPerrorMessage("could not add a node to the clique graph\n"); return SCIP_ERROR; } for ( i = 0; i < actnewnode; i++ ) { /* get adjacent nodes for node newnodes[i] */ firstedge = tcliqueGetFirstAdjedge(probdata->oldgraph, newnodes[i]); lastedge = tcliqueGetLastAdjedge(probdata->oldgraph, newnodes[i]); while ( firstedge <= lastedge ) { /* try to find a node in newnodes which corresponds to the node in the old graph, that is the end-node of the edge */ for ( j = i+1; j < actnewnode; j++ ) { if ( *firstedge == newnodes[j] ) { if( !tcliqueAddEdge(currgraph, i, j) ) { SCIPerrorMessage("could not add an edge to the clique graph\n"); return SCIP_ERROR; } break; } } firstedge++; } } if( !tcliqueFlush(currgraph) ) { SCIPerrorMessage("could not flush the clique graph\n"); return SCIP_ERROR; } /* update currnnodes */ currnnodes = tcliqueGetNNodes(currgraph); /* update new2oldnodes */ for ( i = 0; i < actnewnode; i++ ) { probdata->new2oldnode[i] = newnodes[i]; } /* set the corresponding old node to -1 for all nodes not in the current graph (only for bug-finding) */ for ( i = actnewnode; i < COLORprobGetOriginalNNodes(scip); i++ ) { probdata->new2oldnode[i] = -1; } } } /* end node degree deletion loop */ /* set changed to TRUE for getting into the while-loop */ changed = TRUE; /* loop for finding dominated neighbourhoods */ while ( changed == TRUE ) { changed = FALSE; actnewnode = 0; /* i is the node which is checked for beeing dominated */ for ( i = 0; i < currnnodes; i++ ) { assert(!COLORprobIsNodeInArray(probdata->new2oldnode[i], probdata->deletednodes, ndeletednodes)); /* i must be not in the clique and not yet deleted */ if ( (!COLORprobIsNodeInArray(probdata->new2oldnode[i], maxcliquenodes, nmaxcliquenodes)) ) { /* j is the node for which is checked whether it dominates i */ for ( j = 0; j < currnnodes; j++ ) { /* i must be distinct from j, there must be no edge between i and j, j may not have been deleted due to degree in the last round */ if ( (j != i) && !tcliqueIsEdge(currgraph, i, j) && (!COLORprobIsNodeInArray(probdata->new2oldnode[j], probdata->deletednodes, ndeletednodes)) ) /** @todo only check nodes deleted in the last round */ { /* check whether nodes adjacent to i are also adjacent to j <-> j dominates i */ dominates = TRUE; /* get adjacent nodes for node i in currgraph */ firstedge = tcliqueGetFirstAdjedge(currgraph, i); lastedge = tcliqueGetLastAdjedge(currgraph, i); while ( firstedge <= lastedge ) { /* check whether (j,firstedge) is in currgraph, if not, j doesn't dominate i */ if ( !tcliqueIsEdge(currgraph, j, *firstedge) ) { dominates = FALSE; break; } firstedge++; } if ( dominates ) { probdata->deletednodes[ndeletednodes] = probdata->new2oldnode[i]; changed = TRUE; ndeletednodes++; nnodesdeletedneighbourthisround++; break; /* for j, because we already now that i is dominated and deleted i */ } } } /* end for j */ /* if i is dominated by no other node and thus not deleted, put it into newnodes, so that it is in the next graph */ if ( ndeletednodes == 0 || probdata->deletednodes[ndeletednodes-1] != probdata->new2oldnode[i]) { newnodes[actnewnode] = probdata->new2oldnode[i]; actnewnode++; } } /* if i is in the maxClique und was thus not deleted, put it into newnodes, so that it is in the next graph */ else { newnodes[actnewnode] = probdata->new2oldnode[i]; actnewnode++; } } /*end for i */ /* at least one node was deletet, create new graph ( tclique doesn't support deletion of nodes) */ if ( changed ) { assert(actnewnode+ndeletednodes == COLORprobGetOriginalNNodes(scip)); /* create new current graph */ tcliqueFree(&currgraph); if( !tcliqueCreate(&currgraph) ) { SCIPerrorMessage("could not create the clique graph\n"); return SCIP_ERROR; } assert(currgraph != NULL); if( !tcliqueAddNode(currgraph, actnewnode-1, 0) ) { SCIPerrorMessage("could not add a node to the clique graph\n"); return SCIP_ERROR; } for ( i = 0; i < actnewnode; i++ ) { /* get adjacent nodes for node newnodes[i] */ firstedge = tcliqueGetFirstAdjedge(probdata->oldgraph, newnodes[i]); lastedge = tcliqueGetLastAdjedge(probdata->oldgraph, newnodes[i]); while ( firstedge <= lastedge ) { /* try to find a node in newnodes which corresponds to the node in the old graph, that is the end-node of the edge */ for ( j = i+1; j < actnewnode; j++ ) { if ( *firstedge == newnodes[j] ) { if( !tcliqueAddEdge(currgraph, i, j) ) { SCIPerrorMessage("could not add an edge to the clique graph\n"); return SCIP_ERROR; } break; } } firstedge++; } } if( !tcliqueFlush(currgraph) ) { SCIPerrorMessage("could not flush the clique graph\n"); return SCIP_ERROR; } /* update currnnodes */ currnnodes = tcliqueGetNNodes(currgraph); /* update new2oldnodes */ for ( i = 0; i < actnewnode; i++ ) { probdata->new2oldnode[i] = newnodes[i]; } /* set the corresponding old node to -1 for all nodes not in the current graph (only for bug-finding) */ for ( i = actnewnode; i < COLORprobGetOriginalNNodes(scip); i++ ) { probdata->new2oldnode[i] = -1; } } } /* end of loop for finding dominated neighbourhoods */ printf("Round %d of preprocessing:\n", myround); printf(" deleted low degree vertices: %d\n", nnodesdeleteddegreethisround); printf(" deleted almost cliques: %d\n", nnodesdeletedneighbourthisround); } for ( i = ndeletednodes; i < COLORprobGetOriginalNNodes(scip); i++ ) { probdata->deletednodes[i] = -1; } printf("preprocessing overall deleted vertices: %d\n\n", ndeletednodes); /* copy preprocessed graph into problem data */ probdata->graph = currgraph; SCIPfreeBufferArray(scip, &newnodes); SCIPfreeBufferArray(scip, &maxcliquenodes); return SCIP_OKAY; }
SCIP_RETCODE SCIPconshdlrBenders::sepaBenders( SCIP * scip, SCIP_CONSHDLR * conshdlr, SCIP_SOL * sol, whereFrom where, SCIP_RESULT * result) { OsiCuts cs; /**< Benders cut placeholder */ SCIP_Real * vals = NULL; /**< current solution */ #if 1 if (scip_checkpriority_ < 0) { /** consider incumbent solutions only */ double primObj = SCIPgetPrimalbound(scip); double currObj = SCIPgetSolOrigObj(scip, sol); if (SCIPisLT(scip, primObj, currObj)) { DSPdebugMessage(" -> primObj %e currObj %e\n", primObj, currObj); return SCIP_OKAY; } } #endif /** allocate memory */ SCIP_CALL(SCIPallocMemoryArray(scip, &vals, nvars_)); /** get current solution */ SCIP_CALL(SCIPgetSolVals(scip, sol, nvars_, vars_, vals)); /** TODO The following filter does not work, meaning that it provides suboptimal solution. * I do not know the reason. */ #if 0 double maxviol = 1.e-10; for (int j = 0; j < nvars_ - naux_; ++j) { SCIP_VARTYPE vartype = SCIPvarGetType(vars_[j]); if (vartype == SCIP_VARTYPE_CONTINUOUS) continue; double viol = 0.5 - fabs(vals[j] - floor(vals[j]) - 0.5); if (viol > maxviol) maxviol = viol; } DSPdebugMessage("maximum violation %e\n", maxviol); if (where != from_scip_check && where != from_scip_enfolp && where != from_scip_enfops && maxviol > 1.e-7) { printf("where %d maxviol %e\n", where, maxviol); /** free memory */ SCIPfreeMemoryArray(scip, &vals); return SCIP_OKAY; } #endif #ifdef DSP_DEBUG2 double minvals = COIN_DBL_MAX; double maxvals = -COIN_DBL_MAX; double sumvals = 0.; double ssvals = 0.; //printf("nvars_ %d naux_ %d nAuxvars_ %d\n", nvars_, naux_, tss_->nAuxvars_); for (int j = 0; j < nvars_ - naux_; ++j) { // if (vals[j] < 0 || vals[j] > 1) // printf("solution %d has value %e.\n", j, vals[j]); sumvals += vals[j]; ssvals += vals[j] * vals[j]; minvals = minvals > vals[j] ? vals[j] : minvals; maxvals = maxvals < vals[j] ? vals[j] : maxvals; } DSPdebugMessage("solution: min %e max %e avg %e sum %e two-norm %e\n", minvals, maxvals, sumvals / nvars_, sumvals, sqrt(ssvals)); #endif #define SCAN_GLOBAL_CUT_POOL #ifdef SCAN_GLOBAL_CUT_POOL if (SCIPgetStage(scip) == SCIP_STAGE_SOLVING || SCIPgetStage(scip) == SCIP_STAGE_SOLVED || SCIPgetStage(scip) == SCIP_STAGE_EXITSOLVE) { bool addedPoolCut = false; int numPoolCuts = SCIPgetNPoolCuts(scip); int numCutsToScan = 100; SCIP_CUT ** poolcuts = SCIPgetPoolCuts(scip); for (int i = numPoolCuts - 1; i >= 0; --i) { if (i < 0) break; if (numCutsToScan == 0) break; /** retrieve row */ SCIP_ROW * poolcutrow = SCIPcutGetRow(poolcuts[i]); /** benders? */ if (strcmp(SCIProwGetName(poolcutrow), "benders") != 0) continue; /** counter */ numCutsToScan--; if (SCIPgetCutEfficacy(scip, sol, poolcutrow) > 1.e-6) { if (where == from_scip_sepalp || where == from_scip_sepasol || where == from_scip_enfolp) { /** add cut */ SCIP_Bool infeasible; SCIP_CALL(SCIPaddCut(scip, sol, poolcutrow, FALSE, /**< force cut */ &infeasible)); if (infeasible) *result = SCIP_CUTOFF; else //if (*result != SCIP_CUTOFF) *result = SCIP_SEPARATED; } else *result = SCIP_INFEASIBLE; addedPoolCut = true; break; } } if (addedPoolCut) { DSPdebugMessage("Added pool cut\n"); /** free memory */ SCIPfreeMemoryArray(scip, &vals); return SCIP_OKAY; } } #endif /** generate Benders cuts */ assert(tss_); tss_->generateCuts(nvars_, vals, &cs); /** If found Benders cuts */ for (int i = 0; i < cs.sizeCuts(); ++i) { /** get cut pointer */ OsiRowCut * rc = cs.rowCutPtr(i); if (!rc) continue; const CoinPackedVector cutrow = rc->row(); if (cutrow.getNumElements() == 0) continue; /** is optimality cut? */ bool isOptimalityCut = false; for (int j = nvars_ - naux_; j < nvars_; ++j) { if (cutrow.getMaxIndex() == j) { isOptimalityCut = true; break; } } double efficacy = rc->violated(vals) / cutrow.twoNorm(); SCIP_Bool isEfficacious = efficacy > 1.e-6; #define KK_TEST #ifdef KK_TEST if (SCIPgetStage(scip) == SCIP_STAGE_INITSOLVE || SCIPgetStage(scip) == SCIP_STAGE_SOLVING) { /** create empty row */ SCIP_ROW * row = NULL; SCIP_CALL(SCIPcreateEmptyRowCons(scip, &row, conshdlr, "benders", rc->lb(), SCIPinfinity(scip), FALSE, /**< is row local? */ FALSE, /**< is row modifiable? */ FALSE /**< is row removable? can this be TRUE? */)); /** cache the row extension and only flush them if the cut gets added */ SCIP_CALL(SCIPcacheRowExtensions(scip, row)); /** collect all non-zero coefficients */ for (int j = 0; j < cutrow.getNumElements(); ++j) SCIP_CALL(SCIPaddVarToRow(scip, row, vars_[cutrow.getIndices()[j]], cutrow.getElements()[j])); DSPdebugMessage("found Benders (%s) cut: act=%f, lhs=%f, norm=%f, eff=%f, min=%f, max=%f (range=%f)\n", isOptimalityCut ? "opti" : "feas", SCIPgetRowLPActivity(scip, row), SCIProwGetLhs(row), SCIProwGetNorm(row), SCIPgetCutEfficacy(scip, sol, row), SCIPgetRowMinCoef(scip, row), SCIPgetRowMaxCoef(scip, row), SCIPgetRowMaxCoef(scip, row)/SCIPgetRowMinCoef(scip, row)); /** flush all changes before adding cut */ SCIP_CALL(SCIPflushRowExtensions(scip, row)); DSPdebugMessage("efficacy %e isEfficatious %d\n", efficacy, isEfficacious); if (isEfficacious) { if (where == from_scip_sepalp || where == from_scip_sepasol || where == from_scip_enfolp) { /** add cut */ SCIP_Bool infeasible; SCIP_CALL(SCIPaddCut(scip, sol, row, FALSE, /**< force cut */ &infeasible)); if (infeasible) *result = SCIP_CUTOFF; else //if (*result != SCIP_CUTOFF) *result = SCIP_SEPARATED; } else *result = SCIP_INFEASIBLE; } /** add cut to global pool */ SCIP_CALL(SCIPaddPoolCut(scip, row)); DSPdebugMessage("number of cuts in global cut pool: %d\n", SCIPgetNPoolCuts(scip)); /** release the row */ SCIP_CALL(SCIPreleaseRow(scip, &row)); } else if (isEfficacious && where != from_scip_sepalp && where != from_scip_sepasol && where != from_scip_enfolp) *result = SCIP_INFEASIBLE; #else if (where == from_scip_sepalp || where == from_scip_sepasol || where == from_scip_enfolp) { /** create empty row */ SCIP_ROW * row = NULL; SCIP_CALL(SCIPcreateEmptyRowCons(scip, &row, conshdlr, "benders", rc->lb(), SCIPinfinity(scip), FALSE, /**< is row local? */ FALSE, /**< is row modifiable? */ FALSE /**< is row removable? can this be TRUE? */)); /** cache the row extension and only flush them if the cut gets added */ SCIP_CALL(SCIPcacheRowExtensions(scip, row)); /** collect all non-zero coefficients */ for (int j = 0; j < cutrow.getNumElements(); ++j) SCIP_CALL(SCIPaddVarToRow(scip, row, vars_[cutrow.getIndices()[j]], cutrow.getElements()[j])); DSPdebugMessage("found Benders (%s) cut: act=%f, lhs=%f, norm=%f, eff=%f, min=%f, max=%f (range=%f)\n", isOptimalityCut ? "opti" : "feas", SCIPgetRowLPActivity(scip, row), SCIProwGetLhs(row), SCIProwGetNorm(row), SCIPgetCutEfficacy(scip, NULL, row), SCIPgetRowMinCoef(scip, row), SCIPgetRowMaxCoef(scip, row), SCIPgetRowMaxCoef(scip, row)/SCIPgetRowMinCoef(scip, row)); /** flush all changes before adding cut */ SCIP_CALL(SCIPflushRowExtensions(scip, row)); /** is cut efficacious? */ if (isOptimalityCut) { efficacy = SCIPgetCutEfficacy(scip, sol, row); isEfficacious = SCIPisCutEfficacious(scip, sol, row); } else { efficacy = rc->violated(vals); isEfficacious = efficacy > 1.e-6; } if (isEfficacious) { /** add cut */ SCIP_Bool infeasible; SCIP_CALL(SCIPaddCut(scip, sol, row, FALSE, /**< force cut */ &infeasible)); if (infeasible) *result = SCIP_CUTOFF; else if (*result != SCIP_CUTOFF) *result = SCIP_SEPARATED; } /** add cut to global pool */ SCIP_CALL(SCIPaddPoolCut(scip, row)); /** release the row */ SCIP_CALL(SCIPreleaseRow(scip, &row)); } else { if (isOptimalityCut) { efficacy = rc->violated(vals) / cutrow.twoNorm(); isEfficacious = efficacy > 0.05; } else { efficacy = rc->violated(vals); isEfficacious = efficacy > 1.e-6; } DSPdebugMessage("%s efficacy %e\n", isOptimalityCut ? "Opti" : "Feas", efficacy); if (isEfficacious == TRUE) *result = SCIP_INFEASIBLE; } #endif } /** free memory */ SCIPfreeMemoryArray(scip, &vals); return SCIP_OKAY; }
/** performs the all fullstrong branching */ static SCIP_RETCODE branch( SCIP* scip, /**< SCIP data structure */ SCIP_BRANCHRULE* branchrule, /**< branching rule */ SCIP_Bool allowaddcons, /**< should adding constraints be allowed to avoid a branching? */ SCIP_RESULT* result /**< pointer to store the result of the callback method */ ) { SCIP_BRANCHRULEDATA* branchruledata; SCIP_VAR** pseudocands; SCIP_Real bestdown; SCIP_Real bestup; SCIP_Real bestscore; SCIP_Real provedbound; SCIP_Bool exactsolve; SCIP_Bool allcolsinlp; SCIP_Bool bestdownvalid; SCIP_Bool bestupvalid; int npseudocands; int npriopseudocands; int bestpseudocand; #ifndef NDEBUG SCIP_Real cutoffbound; cutoffbound = SCIPgetCutoffbound(scip); #endif assert(branchrule != NULL); assert(strcmp(SCIPbranchruleGetName(branchrule), BRANCHRULE_NAME) == 0); assert(scip != NULL); assert(result != NULL); /* check, if all existing columns are in LP, and thus the strong branching results give lower bounds */ allcolsinlp = SCIPallColsInLP(scip); /* check, if we want to solve the problem exactly, meaning that strong branching information is not useful * for cutting off sub problems and improving lower bounds of children */ exactsolve = SCIPisExactSolve(scip); /* get branching rule data */ branchruledata = SCIPbranchruleGetData(branchrule); assert(branchruledata != NULL); if( branchruledata->skipdown == NULL ) { int nvars; nvars = SCIPgetNVars(scip); assert(branchruledata->skipup == NULL); SCIP_CALL( SCIPallocMemoryArray(scip, &branchruledata->skipdown, nvars) ); SCIP_CALL( SCIPallocMemoryArray(scip, &branchruledata->skipup, nvars) ); BMSclearMemoryArray(branchruledata->skipdown, nvars); BMSclearMemoryArray(branchruledata->skipup, nvars); } /* get all non-fixed variables (not only the fractional ones) */ SCIP_CALL( SCIPgetPseudoBranchCands(scip, &pseudocands, &npseudocands, &npriopseudocands) ); assert(npseudocands > 0); assert(npriopseudocands > 0); SCIP_CALL( SCIPselectVarPseudoStrongBranching(scip, pseudocands, branchruledata->skipdown, branchruledata->skipup, npseudocands, npriopseudocands, allowaddcons, &bestpseudocand, &bestdown, &bestup, &bestscore, &bestdownvalid, &bestupvalid, &provedbound, result) ); if( *result != SCIP_CUTOFF && *result != SCIP_REDUCEDDOM && *result != SCIP_CONSADDED ) { SCIP_NODE* downchild; SCIP_NODE* eqchild; SCIP_NODE* upchild; SCIP_VAR* var; assert(*result == SCIP_DIDNOTRUN); assert(0 <= bestpseudocand && bestpseudocand < npseudocands); assert(SCIPisLT(scip, provedbound, cutoffbound)); var = pseudocands[bestpseudocand]; /* perform the branching */ SCIPdebugMessage(" -> %d candidates, selected candidate %d: variable <%s>[%g,%g] (solval=%g, down=%g, up=%g, score=%g)\n", npseudocands, bestpseudocand, SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), SCIPvarGetLPSol(var), bestdown, bestup, bestscore); SCIP_CALL( SCIPbranchVarVal(scip, var, SCIPvarGetLPSol(var), &downchild, &eqchild, &upchild) ); /* update the lower bounds in the children */ if( allcolsinlp && !exactsolve ) { if( downchild != NULL ) { SCIP_CALL( SCIPupdateNodeLowerbound(scip, downchild, bestdownvalid ? MAX(bestdown, provedbound) : provedbound) ); SCIPdebugMessage(" -> down child's lowerbound: %g\n", SCIPnodeGetLowerbound(downchild)); } if( eqchild != NULL ) { SCIP_CALL( SCIPupdateNodeLowerbound(scip, eqchild, provedbound) ); SCIPdebugMessage(" -> eq child's lowerbound: %g\n", SCIPnodeGetLowerbound(eqchild)); } if( upchild != NULL ) { SCIP_CALL( SCIPupdateNodeLowerbound(scip, upchild, bestupvalid ? MAX(bestup, provedbound) : provedbound) ); SCIPdebugMessage(" -> up child's lowerbound: %g\n", SCIPnodeGetLowerbound(upchild)); } } *result = SCIP_BRANCHED; } return SCIP_OKAY; }
/** reads an objective or constraint with name and coefficients */ static SCIP_RETCODE readCoefficients( SCIP* scip, /**< SCIP data structure */ LPINPUT* lpinput, /**< LP reading data */ SCIP_Bool isobjective, /**< indicates whether we are currently reading the coefficients of the objective */ char* name, /**< pointer to store the name of the line; must be at least of size * LP_MAX_LINELEN */ SCIP_VAR*** vars, /**< pointer to store the array with variables (must be freed by caller) */ SCIP_Real** coefs, /**< pointer to store the array with coefficients (must be freed by caller) */ int* ncoefs, /**< pointer to store the number of coefficients */ SCIP_Bool* newsection /**< pointer to store whether a new section was encountered */ ) { SCIP_Bool havesign; SCIP_Bool havevalue; SCIP_Real coef; int coefsign; int coefssize; assert(lpinput != NULL); assert(name != NULL); assert(vars != NULL); assert(coefs != NULL); assert(ncoefs != NULL); assert(newsection != NULL); *vars = NULL; *coefs = NULL; *name = '\0'; *ncoefs = 0; *newsection = FALSE; /* read the first token, which may be the name of the line */ if( getNextToken(scip, lpinput) ) { /* check if we reached a new section */ if( isNewSection(scip, lpinput) ) { *newsection = TRUE; return SCIP_OKAY; } /* remember the token in the token buffer */ swapTokenBuffer(lpinput); /* get the next token and check, whether it is a colon */ if( getNextToken(scip, lpinput) ) { if( strcmp(lpinput->token, ":") == 0 ) { /* the second token was a colon: the first token is the line name */ (void)SCIPmemccpy(name, lpinput->tokenbuf, '\0', LP_MAX_LINELEN); name[LP_MAX_LINELEN - 1] = '\0'; SCIPdebugMessage("(line %d) read constraint name: '%s'\n", lpinput->linenumber, name); } else { /* the second token was no colon: push the tokens back onto the token stack and parse them as coefficients */ pushToken(lpinput); pushBufferToken(lpinput); } } else { /* there was only one token left: push it back onto the token stack and parse it as coefficient */ pushBufferToken(lpinput); } } /* initialize buffers for storing the coefficients */ coefssize = LP_INIT_COEFSSIZE; SCIP_CALL( SCIPallocMemoryArray(scip, vars, coefssize) ); SCIP_CALL( SCIPallocMemoryArray(scip, coefs, coefssize) ); /* read the coefficients */ coefsign = +1; coef = 1.0; havesign = FALSE; havevalue = FALSE; *ncoefs = 0; while( getNextToken(scip, lpinput) ) { SCIP_VAR* var; /* check if we read a sign */ if( isSign(lpinput, &coefsign) ) { SCIPdebugMessage("(line %d) read coefficient sign: %+d\n", lpinput->linenumber, coefsign); havesign = TRUE; continue; } /* check if we read a value */ if( isValue(scip, lpinput, &coef) ) { SCIPdebugMessage("(line %d) read coefficient value: %g with sign %+d\n", lpinput->linenumber, coef, coefsign); if( havevalue ) { syntaxError(scip, lpinput, "two consecutive values."); return SCIP_OKAY; } havevalue = TRUE; continue; } /* check if we reached an equation sense */ if( isSense(lpinput, NULL) ) { if( isobjective ) { syntaxError(scip, lpinput, "no sense allowed in objective"); return SCIP_OKAY; } /* put the sense back onto the token stack */ pushToken(lpinput); break; } /* check if we reached a new section, that will be only allowed when having no current sign and value and if we * are not in the quadratic part */ if( (isobjective || (!havevalue && !havesign)) && isNewSection(scip, lpinput) ) { if( havesign && !havevalue ) { SCIPwarningMessage(scip, "skipped single sign %c without value or variable in objective\n", coefsign == 1 ? '+' : '-'); } else if( isobjective && havevalue && !SCIPisZero(scip, coef) ) { SCIPwarningMessage(scip, "constant term %+g in objective is skipped\n", coef * coefsign); } *newsection = TRUE; return SCIP_OKAY; } /* check if we start a quadratic part */ if( *lpinput->token == '[' ) { syntaxError(scip, lpinput, "diff reader does not support quadratic objective function."); return SCIP_READERROR; } /* all but the first coefficient need a sign */ if( *ncoefs > 0 && !havesign ) { syntaxError(scip, lpinput, "expected sign ('+' or '-') or sense ('<' or '>')."); return SCIP_OKAY; } /* check if the last variable should be squared */ if( *lpinput->token == '^' ) { syntaxError(scip, lpinput, "diff reader does not support quadratic objective function."); return SCIP_READERROR; } else { /* the token is a variable name: get the corresponding variable */ SCIP_CALL( getVariable(scip, lpinput->token, &var) ); } /* insert the linear coefficient */ SCIPdebugMessage("(line %d) read linear coefficient: %+g<%s>\n", lpinput->linenumber, coefsign * coef, SCIPvarGetName(var)); if( !SCIPisZero(scip, coef) ) { /* resize the vars and coefs array if needed */ if( *ncoefs >= coefssize ) { coefssize *= 2; coefssize = MAX(coefssize, (*ncoefs)+1); SCIP_CALL( SCIPreallocMemoryArray(scip, vars, coefssize) ); SCIP_CALL( SCIPreallocMemoryArray(scip, coefs, coefssize) ); } assert(*ncoefs < coefssize); /* add coefficient */ (*vars)[*ncoefs] = var; (*coefs)[*ncoefs] = coefsign * coef; (*ncoefs)++; } /* reset the flags and coefficient value for the next coefficient */ coefsign = +1; coef = 1.0; havesign = FALSE; havevalue = FALSE; } return SCIP_OKAY; }
/** method for either Farkas or Redcost pricing */ static SCIP_RETCODE pricing( SCIP* scip, /**< SCIP data structure */ SCIP_PRICER* pricer, /**< pricer */ SCIP_Real* lowerbound, /**< lowerbound pointer */ SCIP_Bool farkas /**< TRUE: Farkas pricing; FALSE: Redcost pricing */ ) { SCIP_PRICERDATA* pricerdata; /* the data of the pricer */ SCIP_PROBDATA* probdata; GRAPH* graph; SCIP_VAR* var; PATH* path; SCIP_Real* edgecosts; /* edgecosts of the current subproblem */ char varname[SCIP_MAXSTRLEN]; SCIP_Real newlowerbound = -SCIPinfinity(scip); SCIP_Real redcost; /* reduced cost */ int tail; int e; int t; int i; assert(scip != NULL); assert(pricer != NULL); /* get pricer data */ pricerdata = SCIPpricerGetData(pricer); assert(pricerdata != NULL); /* get problem data */ probdata = SCIPgetProbData(scip); assert(probdata != NULL); SCIPdebugMessage("solstat=%d\n", SCIPgetLPSolstat(scip)); if( !farkas && SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL ) newlowerbound = SCIPgetSolTransObj(scip, NULL); SCIPdebug( SCIP_CALL( SCIPprintSol(scip, NULL, NULL, FALSE) ) ); # if 0 if ( pricerdata->lowerbound <= 4 ) { char label[SCIP_MAXSTRLEN]; (void)SCIPsnprintf(label, SCIP_MAXSTRLEN, "X%g.gml", pricerdata->lowerbound); SCIP_CALL( SCIPprobdataPrintGraph(scip, label , NULL, TRUE) ); pricerdata->lowerbound++; } #endif /* get the graph*/ graph = SCIPprobdataGetGraph(probdata); /* get dual solutions and save them in mi and pi */ for( t = 0; t < pricerdata->realnterms; ++t ) { if( farkas ) { pricerdata->mi[t] = SCIPgetDualfarkasLinear(scip, pricerdata->pathcons[t]); } else { pricerdata->mi[t] = SCIPgetDualsolLinear(scip, pricerdata->pathcons[t]); assert(!SCIPisNegative(scip, pricerdata->mi[t])); } } for( e = 0; e < pricerdata->nedges; ++e ) { if( !pricerdata->bigt ) { for( t = 0; t < pricerdata->realnterms; ++t ) { if( farkas ) { pricerdata->pi[t * pricerdata->nedges + e] = SCIPgetDualfarkasLinear( scip, pricerdata->edgecons[t * pricerdata->nedges + e]); } else { pricerdata->pi[t * pricerdata->nedges + e] = SCIPgetDualsolLinear( scip, pricerdata->edgecons[t * pricerdata->nedges + e]); } } } else { if( farkas ) { pricerdata->pi[e] = SCIPgetDualfarkasLinear( scip, pricerdata->edgecons[e]); } else { pricerdata->pi[e] = SCIPgetDualsolLinear( scip, pricerdata->edgecons[e]); } } } SCIP_CALL( SCIPallocMemoryArray(scip, &path, graph->knots) ); SCIP_CALL( SCIPallocMemoryArray(scip, &edgecosts, pricerdata->nedges) ); if( pricerdata->bigt ) { for( e = 0; e < pricerdata->nedges; ++e ) { edgecosts[e] = (-pricerdata->pi[e]); } } /* find shortest r-t (r root, t terminal) paths and create corresponding variables iff reduced cost < 0 */ for( t = 0; t < pricerdata->realnterms; ++t ) { for( e = 0; e < pricerdata->nedges; ++e ) { if( !pricerdata->bigt ) { edgecosts[e] = (-pricerdata->pi[t * pricerdata->nedges + e]); } assert(!SCIPisNegative(scip, edgecosts[e])); } for( i = 0; i < graph->knots; i++ ) graph->mark[i] = 1; graph_path_exec(scip, graph, FSP_MODE, pricerdata->root, edgecosts, path); /* compute reduced cost of shortest path to terminal t */ redcost = 0.0; tail = pricerdata->realterms[t]; while( tail != pricerdata->root ) { redcost += edgecosts[path[tail].edge]; tail = graph->tail[path[tail].edge]; } redcost -= pricerdata->mi[t]; if( !farkas && SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL ) { newlowerbound += redcost; } /* check if reduced cost < 0 */ if( SCIPisNegative(scip, redcost) ) { /* create variable to the shortest path (having reduced cost < 0) */ var = NULL; sprintf(varname, "PathVar%d_%d", t, pricerdata->ncreatedvars[t]); ++(pricerdata->ncreatedvars[t]); SCIP_CALL( SCIPcreateVarBasic(scip, &var, varname, 0.0, SCIPinfinity(scip), 0.0, SCIP_VARTYPE_CONTINUOUS) ); SCIP_CALL( SCIPaddPricedVar(scip, var, -redcost) ); tail = pricerdata->realterms[t]; while( tail != pricerdata->root ) { /* add variable to constraints */ if( !pricerdata->bigt ) { SCIP_CALL( SCIPaddCoefLinear(scip, pricerdata->edgecons[t * pricerdata->nedges + path[tail].edge], var, 1.0) ); } else { SCIP_CALL( SCIPaddCoefLinear(scip, pricerdata->edgecons[path[tail].edge], var, 1.0) ); } tail = graph->tail[path[tail].edge]; } SCIP_CALL( SCIPaddCoefLinear(scip, pricerdata->pathcons[t], var, 1.0) ); } } if( !farkas && SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL ) *lowerbound = newlowerbound; SCIPfreeMemoryArray(scip, &edgecosts); SCIPfreeMemoryArray(scip, &path); return SCIP_OKAY; }
/** reduced cost pricing method of variable pricer for feasible LPs */ static SCIP_DECL_PRICERREDCOST(pricerRedcostBinpacking) { /*lint --e{715}*/ SCIP* subscip; SCIP_PRICERDATA* pricerdata; SCIP_CONS** conss; SCIP_VAR** vars; int* ids; SCIP_Bool addvar; SCIP_SOL** sols; int nsols; int s; int nitems; SCIP_Longint capacity; SCIP_Real timelimit; SCIP_Real memorylimit; assert(scip != NULL); assert(pricer != NULL); (*result) = SCIP_DIDNOTRUN; /* get the pricer data */ pricerdata = SCIPpricerGetData(pricer); assert(pricerdata != NULL); capacity = pricerdata->capacity; conss = pricerdata->conss; ids = pricerdata->ids; nitems = pricerdata->nitems; /* get the remaining time and memory limit */ SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) ); if( !SCIPisInfinity(scip, timelimit) ) timelimit -= SCIPgetSolvingTime(scip); SCIP_CALL( SCIPgetRealParam(scip, "limits/memory", &memorylimit) ); if( !SCIPisInfinity(scip, memorylimit) ) memorylimit -= SCIPgetMemUsed(scip)/1048576.0; /* initialize SCIP */ SCIP_CALL( SCIPcreate(&subscip) ); SCIP_CALL( SCIPincludeDefaultPlugins(subscip) ); /* create problem in sub SCIP */ SCIP_CALL( SCIPcreateProbBasic(subscip, "pricing") ); SCIP_CALL( SCIPsetObjsense(subscip, SCIP_OBJSENSE_MAXIMIZE) ); /* 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 time and memory limit */ SCIP_CALL( SCIPsetRealParam(subscip, "limits/time", timelimit) ); SCIP_CALL( SCIPsetRealParam(subscip, "limits/memory", memorylimit) ); SCIP_CALL( SCIPallocMemoryArray(subscip, &vars, nitems) ); /* initialization local pricing problem */ SCIP_CALL( initPricing(scip, pricerdata, subscip, vars) ); SCIPdebugMessage("solve pricer problem\n"); /* solve sub SCIP */ SCIP_CALL( SCIPsolve(subscip) ); sols = SCIPgetSols(subscip); nsols = SCIPgetNSols(subscip); addvar = FALSE; /* loop over all solutions and create the corresponding column to master if the reduced cost are negative for master, * that is the objective value i greater than 1.0 */ for( s = 0; s < nsols; ++s ) { SCIP_Bool feasible; SCIP_SOL* sol; /* the soultion should be sorted w.r.t. the objective function value */ assert(s == 0 || SCIPisFeasGE(subscip, SCIPgetSolOrigObj(subscip, sols[s-1]), SCIPgetSolOrigObj(subscip, sols[s]))); sol = sols[s]; assert(sol != NULL); /* check if solution is feasible in original sub SCIP */ SCIP_CALL( SCIPcheckSolOrig(subscip, sol, &feasible, FALSE, FALSE ) ); if( !feasible ) { SCIPwarningMessage(scip, "solution in pricing problem (capacity <%d>) is infeasible\n", capacity); continue; } /* check if the solution has a value greater than 1.0 */ if( SCIPisFeasGT(subscip, SCIPgetSolOrigObj(subscip, sol), 1.0) ) { SCIP_VAR* var; SCIP_VARDATA* vardata; int* consids; char strtmp[SCIP_MAXSTRLEN]; char name[SCIP_MAXSTRLEN]; int nconss; int o; int v; SCIPdebug( SCIP_CALL( SCIPprintSol(subscip, sol, NULL, FALSE) ) ); nconss = 0; (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "items"); SCIP_CALL( SCIPallocBufferArray(scip, &consids, nitems) ); /* check which variables are fixed -> which item belongs to this packing */ for( o = 0, v = 0; o < nitems; ++o ) { if( !SCIPconsIsEnabled(conss[o]) ) continue; assert(SCIPgetNFixedonesSetppc(scip, conss[o]) == 0); if( SCIPgetSolVal(subscip, sol, vars[v]) > 0.5 ) { (void) SCIPsnprintf(strtmp, SCIP_MAXSTRLEN, "_%d", ids[o]); strcat(name, strtmp); consids[nconss] = o; nconss++; } else assert( SCIPisFeasEQ(subscip, SCIPgetSolVal(subscip, sol, vars[v]), 0.0) ); v++; } SCIP_CALL( SCIPvardataCreateBinpacking(scip, &vardata, consids, nconss) ); /* create variable for a new column with objective function coefficient 0.0 */ SCIP_CALL( SCIPcreateVarBinpacking(scip, &var, name, 1.0, FALSE, TRUE, vardata) ); /* add the new variable to the pricer store */ SCIP_CALL( SCIPaddPricedVar(scip, var, 1.0) ); addvar = TRUE; /* change the upper bound of the binary variable to lazy since the upper bound is already enforced due to * the objective function the set covering constraint; The reason for doing is that, is to avoid the bound * of x <= 1 in the LP relaxation since this bound constraint would produce a dual variable which might have * a positive reduced cost */ SCIP_CALL( SCIPchgVarUbLazy(scip, var, 1.0) ); /* check which variable are fixed -> which orders belong to this packing */ for( v = 0; v < nconss; ++v ) { assert(SCIPconsIsEnabled(conss[consids[v]])); SCIP_CALL( SCIPaddCoefSetppc(scip, conss[consids[v]], var) ); } SCIPdebug(SCIPprintVar(scip, var, NULL) ); SCIP_CALL( SCIPreleaseVar(scip, &var) ); SCIPfreeBufferArray(scip, &consids); } else break; } /* free pricer MIP */ SCIPfreeMemoryArray(subscip, &vars); if( addvar || SCIPgetStatus(subscip) == SCIP_STATUS_OPTIMAL ) (*result) = SCIP_SUCCESS; /* free sub SCIP */ SCIP_CALL( SCIPfree(&subscip) ); return SCIP_OKAY; }