/** creates a subproblem for subscip by fixing a number of variables */ static SCIP_RETCODE setupSubproblem( SCIP* scip, /**< original SCIP data structure */ SCIP* subscip, /**< SCIP data structure for the subproblem */ SCIP_VAR** subvars, /**< the variables of the subproblem */ int* selection, /**< pool of solutions crossover will use */ SCIP_HEURDATA* heurdata, /**< primal heuristic data */ SCIP_Bool* success /**< pointer to store whether the problem was created successfully */ ) { SCIP_SOL** sols; /* array of all solutions found so far */ int nsols; /* number of all solutions found so far */ int nusedsols; /* number of solutions to use in crossover */ int i; char consname[SCIP_MAXSTRLEN]; /* get solutions' data */ nsols = SCIPgetNSols(scip); sols = SCIPgetSols(scip); nusedsols = heurdata->nusedsols; assert(nusedsols > 1); assert(nsols >= nusedsols); /* use nusedsols best solutions if randomization is deactivated or there are only nusedsols solutions at hand * or a good new solution was found since last call */ if( !heurdata->randomization || nsols == nusedsols || heurdata->prevlastsol != sols[nusedsols-1] ) { SOLTUPLE* elem; SCIP_HEUR* solheur; SCIP_Longint solnodenum; SCIP_Bool allsame; for( i = 0; i < nusedsols; i++ ) selection[i] = i; SCIP_CALL( createSolTuple(scip, &elem, selection, nusedsols, heurdata) ); solheur = SCIPsolGetHeur(sols[0]); solnodenum = SCIPsolGetNodenum(sols[0]); allsame = TRUE; /* check, whether all solutions have been found by the same heuristic at the same node; in this case we do not run * crossover, since it would probably just optimize over the same space as the other heuristic */ for( i = 1; i < nusedsols; i++ ) { if( SCIPsolGetHeur(sols[i]) != solheur || SCIPsolGetNodenum(sols[i]) != solnodenum ) allsame = FALSE; } *success = !allsame && !SCIPhashtableExists(heurdata->hashtable, elem); /* check, whether solution tuple has already been tried */ if( !SCIPhashtableExists(heurdata->hashtable, elem) ) { SCIP_CALL( SCIPhashtableInsert(heurdata->hashtable, elem) ); } /* if solution tuple has already been tried, randomization is allowed and enough solutions are at hand, try * to randomize another tuple. E.g., this can happen if the last crossover solution was among the best ones */ if( !(*success) && heurdata->randomization && nsols > nusedsols ) { SCIP_CALL( selectSolsRandomized(scip, selection, heurdata, success) ); } } /* otherwise randomize the set of solutions */ else { SCIP_CALL( selectSolsRandomized(scip, selection, heurdata, success) ); } /* no acceptable solution tuple could be created */ if( !(*success) ) return SCIP_OKAY; /* get name of the original problem and add the string "_crossoversub" */ (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "%s_crossoversub", SCIPgetProbName(scip)); /* set up the variables of the subproblem */ SCIP_CALL( fixVariables(scip, subscip, subvars, selection, heurdata, success) ); /* we copy the rows of the LP, if the enough variables could be fixed and we work on the MIP relaxation of the problem */ if( *success && heurdata->uselprows ) { SCIP_CALL( createRows(scip, subscip, subvars) ); } return SCIP_OKAY; }
/** problem writing method of reader */ static SCIP_DECL_READERWRITE(readerWriteCip) { /*lint --e{715}*/ SCIP_HASHTABLE* varhash = NULL; SCIP_READERDATA* readerdata; int i; assert(reader != NULL); assert(strcmp(SCIPreaderGetName(reader), READER_NAME) == 0); SCIPinfoMessage(scip, file, "STATISTICS\n"); SCIPinfoMessage(scip, file, " Problem name : %s\n", name); SCIPinfoMessage(scip, file, " Variables : %d (%d binary, %d integer, %d implicit integer, %d continuous)\n", nvars, nbinvars, nintvars, nimplvars, ncontvars); SCIPinfoMessage(scip, file, " Constraints : %d initial, %d maximal\n", startnconss, maxnconss); SCIPinfoMessage(scip, file, "OBJECTIVE\n"); SCIPinfoMessage(scip, file, " Sense : %s\n", objsense == SCIP_OBJSENSE_MINIMIZE ? "minimize" : "maximize"); if( !SCIPisZero(scip, objoffset) ) SCIPinfoMessage(scip, file, " Offset : %+.15g\n", objoffset); if( !SCIPisEQ(scip, objscale, 1.0) ) SCIPinfoMessage(scip, file, " Scale : %.15g\n", objscale); if ( nfixedvars > 0 ) { /* set up hash table for variables that have been written property (used for writing out fixed vars in the right order) */ SCIP_CALL( SCIPhashtableCreate(&varhash, SCIPblkmem(scip), SCIPcalcHashtableSize(10 * (nvars + nfixedvars)), hashGetKeyVar, hashKeyEqVar, hashKeyValVar, NULL) ); } if ( nvars + nfixedvars > 0 ) { SCIPinfoMessage(scip, file, "VARIABLES\n"); } if( nvars > 0 ) { for( i = 0; i < nvars; ++i ) { SCIP_VAR* var; var = vars[i]; assert( var != NULL ); SCIP_CALL( SCIPprintVar(scip, var, file) ); if ( varhash != NULL ) { /* add free variable to hashtable */ if ( ! SCIPhashtableExists(varhash, (void*) var) ) { SCIP_CALL( SCIPhashtableInsert(varhash, (void*) var) ); } } } } readerdata = SCIPreaderGetData(reader); assert(readerdata != NULL); if( readerdata->writefixedvars && nfixedvars > 0 ) { int nwritten = 0; SCIPinfoMessage(scip, file, "FIXED\n"); /* loop through variables until each has been written after the variables that it depends on have been written; this * requires several runs over the variables, but the depth (= number of loops) is usually small. */ while ( nwritten < nfixedvars ) { SCIPdebugMessage("written %d of %d fixed variables.\n", nwritten, nfixedvars); for (i = 0; i < nfixedvars; ++i) { SCIP_VAR* var; SCIP_VAR* tmpvar; var = fixedvars[i]; assert( var != NULL ); /* skip variables already written */ if ( SCIPhashtableExists(varhash, (void*) var) ) continue; switch ( SCIPvarGetStatus(var) ) { case SCIP_VARSTATUS_FIXED: /* fixed variables can simply be output and added to the hashtable */ SCIP_CALL( SCIPprintVar(scip, var, file) ); assert( ! SCIPhashtableExists(varhash, (void*) var) ); SCIP_CALL( SCIPhashtableInsert(varhash, (void*) var) ); ++nwritten; break; case SCIP_VARSTATUS_NEGATED: tmpvar = SCIPvarGetNegationVar(var); assert( tmpvar != NULL ); assert( var == SCIPvarGetNegatedVar(tmpvar) ); /* if the negated variable has been written, we can write the current variable */ if ( SCIPhashtableExists(varhash, (void*) tmpvar) ) { SCIP_CALL( SCIPprintVar(scip, var, file) ); assert( ! SCIPhashtableExists(varhash, (void*) var) ); SCIP_CALL( SCIPhashtableInsert(varhash, (void*) var) ); ++nwritten; } break; case SCIP_VARSTATUS_AGGREGATED: tmpvar = SCIPvarGetAggrVar(var); assert( tmpvar != NULL ); /* if the aggregating variable has been written, we can write the current variable */ if ( SCIPhashtableExists(varhash, (void*) tmpvar) ) { SCIP_CALL( SCIPprintVar(scip, var, file) ); assert( ! SCIPhashtableExists(varhash, (void*) var) ); SCIP_CALL( SCIPhashtableInsert(varhash, (void*) var) ); ++nwritten; } break; case SCIP_VARSTATUS_MULTAGGR: { SCIP_VAR** aggrvars; int naggrvars; int j; /* get the active representation */ SCIP_CALL( SCIPflattenVarAggregationGraph(scip, var) ); naggrvars = SCIPvarGetMultaggrNVars(var); aggrvars = SCIPvarGetMultaggrVars(var); assert(aggrvars != NULL || naggrvars == 0); for (j = 0; j < naggrvars; ++j) { if( !SCIPhashtableExists(varhash, (void*) aggrvars[j]) ) /*lint !e613*/ break; } /* if all multi-aggregating variables have been written, we can write the current variable */ if ( j >= naggrvars ) { SCIP_CALL( SCIPprintVar(scip, var, file) ); assert( ! SCIPhashtableExists(varhash, (void*) var) ); SCIP_CALL( SCIPhashtableInsert(varhash, (void*) var) ); ++nwritten; } break; } case SCIP_VARSTATUS_ORIGINAL: case SCIP_VARSTATUS_LOOSE: case SCIP_VARSTATUS_COLUMN: SCIPerrorMessage("Only fixed variables are allowed to be present in fixedvars list.\n"); SCIPABORT(); return SCIP_ERROR; /*lint !e527*/ } } } } if( nconss > 0 ) { SCIPinfoMessage(scip, file, "CONSTRAINTS\n"); for( i = 0; i < nconss; ++i ) { SCIP_CALL( SCIPprintCons(scip, conss[i], file) ); SCIPinfoMessage(scip, file, ";\n"); } } SCIPinfoMessage(scip, file, "END\n"); *result = SCIP_SUCCESS; if( nfixedvars > 0 ) SCIPhashtableFree(&varhash); else assert(varhash == NULL); return SCIP_OKAY; }
/** randomly selects the solutions crossover will use from the pool of all solutions found so far */ static SCIP_RETCODE selectSolsRandomized( SCIP* scip, /**< original SCIP data structure */ int* selection, /**< pool of solutions crossover uses */ SCIP_HEURDATA* heurdata, /**< primal heuristic data */ SCIP_Bool* success /**< pointer to store whether the process was successful */ ) { int i; int j; int lastsol; /* the worst solution possible to choose */ int nusedsols; /* number of solutions which will be chosen */ SOLTUPLE* elem; SCIP_SOL** sols; /* initialization */ nusedsols = heurdata->nusedsols; lastsol = SCIPgetNSols(scip); sols = SCIPgetSols(scip); assert(nusedsols < lastsol); i = 0; *success = FALSE; /* perform at maximum 10 restarts and stop as soon as a new set of solutions is found */ while( !*success && i < 10 ) { SCIP_Bool validtuple; validtuple = TRUE; for( j = 0; j < nusedsols && validtuple; j++ ) { int k; k = SCIPgetRandomInt(nusedsols-j-1, lastsol-1, &heurdata->randseed); /* ensure that the solution does not have a similar source as the others */ while( k >= nusedsols-j-1 && !solHasNewSource(sols, selection, j, k) ) k--; validtuple = (k >= nusedsols-j-1); selection[j] = k; lastsol = k; } if( validtuple ) { /* creates an object ready to be inserted into the hashtable */ SCIP_CALL( createSolTuple(scip, &elem, selection, nusedsols, heurdata) ); /* check whether the randomized set is already in the hashtable, if not, insert it */ if( !SCIPhashtableExists(heurdata->hashtable, elem) ) { SCIP_CALL( SCIPhashtableInsert(heurdata->hashtable, elem) ); *success = TRUE; } } i++; } return SCIP_OKAY; }