int main(int argc, char **argv) { char *f_name_lp, *last_dot_pos, f_name[256], *f_name_pos; int i, ncol; if((argc < 2) || (argc > 2)) { printf("### ERROR: main(): Usage: One of the following\ncgl_data_test input_file_name.mps\ncgl_data_test input_file_name.lp\n"); exit(1); } f_name_lp = strdup(argv[1]); f_name_pos = strrchr(f_name_lp, '/'); if(f_name_pos != NULL) { strcpy(f_name, &(f_name_pos[1])); } else { strcpy(f_name, f_name_lp); } last_dot_pos = strrchr(f_name, '.'); if(last_dot_pos != NULL) { last_dot_pos = '\0'; } OsiClpSolverInterface *clp = new OsiClpSolverInterface; clp->messageHandler()->setLogLevel(0); if(strcmp(&(f_name_lp[strlen(f_name_lp)-3]), ".lp") == 0) { clp->readLp(f_name_lp); } else { if(strcmp(&(f_name_lp[strlen(f_name_lp)-4]), ".mps") == 0) { clp->readMps(f_name_lp); } else { printf("### ERROR: unrecognized file type\n"); exit(1); } } ncol = clp->getNumCols(); clp->initialSolve(); printf("LP value: %12.2f\n", clp->getObjValue()); OsiCuts cuts; // Define parameters for CglRedSplit generator CglParam cpar; cpar.setMAX_SUPPORT(ncol+1); CglRedSplitParam rspar(cpar); // Create a cut generator with the given parameters CglRedSplit cutGen(rspar); char *colType = new char[ncol]; for(i=0; i<ncol; i++) { if(clp->isContinuous(i)) { colType[i] = 'C'; } else { colType[i] = 'I'; } } int round, max_rounds = 10; for(round=0; round<max_rounds; round++) { cutGen.generateCuts(*clp, cuts); int ncuts = cuts.sizeRowCuts(); const OsiRowCut **newRowCuts = new const OsiRowCut * [ncuts]; for(i=0; i<ncuts; i++) { newRowCuts[i] = &cuts.rowCut(i); } clp->applyRowCuts(ncuts, newRowCuts); delete[] newRowCuts; printf("round %4d: %4d generated cuts new objective value: %12.2f\n", round, ncuts, clp->getObjValue()); clp->resolve(); if(clp->isAbandoned()) { printf("###ERROR: Numerical difficulties in Solver\n"); exit(1); } if(clp->isProvenPrimalInfeasible()) { printf("### WARNING: Problem is infeasible\n"); exit(1); } } delete clp; free(f_name_lp); delete[] colType; return(0); }
/* Randomized Rounding Heuristic Returns 1 if solution, 0 if not */ int CbcHeuristicRandRound::solution(double & solutionValue, double * betterSolution) { // rlh: Todo: Memory Cleanup // std::cout << "Entering the Randomized Rounding Heuristic" << std::endl; setWhen(1); // setWhen(1) didn't have the effect I expected (e.g., run once). // Run only once. // // See if at root node bool atRoot = model_->getNodeCount() == 0; int passNumber = model_->getCurrentPassNumber(); // Just do once if (!atRoot || passNumber > 1) { // std::cout << "Leaving the Randomized Rounding Heuristic" << std::endl; return 0; } std::cout << "Entering the Randomized Rounding Heuristic" << std::endl; typedef struct { int numberSolutions; int maximumSolutions; int numberColumns; double ** solution; int * numberUnsatisfied; } clpSolution; double start = CoinCpuTime(); numCouldRun_++; // #ifdef HEURISTIC_INFORM printf("Entering heuristic %s - nRuns %d numCould %d when %d\n", heuristicName(),numRuns_,numCouldRun_,when_); #endif // Todo: Ask JJHF what "number of times // the heuristic could run" means. OsiSolverInterface * solver = model_->solver()->clone(); double primalTolerance ; solver->getDblParam(OsiPrimalTolerance, primalTolerance) ; OsiClpSolverInterface * clpSolver = dynamic_cast<OsiClpSolverInterface *> (solver); assert (clpSolver); ClpSimplex * simplex = clpSolver->getModelPtr(); // Initialize the structure holding the solutions for the Simplex iterations clpSolution solutions; // Set typeStruct field of ClpTrustedData struct to 1 to indicate // desired behavior for RandRound heuristic (which is what?) ClpTrustedData trustedSolutions; trustedSolutions.typeStruct = 1; trustedSolutions.data = &solutions; solutions.numberSolutions = 0; solutions.maximumSolutions = 0; solutions.numberColumns = simplex->numberColumns(); solutions.solution = NULL; solutions.numberUnsatisfied = NULL; simplex->setTrustedUserPointer(&trustedSolutions); // Solve from all slack to get some points simplex->allSlackBasis(); // Calling primal() invalidates pointers to some rim vectors, // like...row sense (!) simplex->primal(); // 1. Okay - so a workaround would be to copy the data I want BEFORE // calling primal. // 2. Another approach is to ask the simplex solvers NOT to mess up my // rims. // 3. See freeCachedResults() for what is getting // deleted. Everything else points into the structure. // ...or use collower and colupper rather than rowsense. // ..store address of where one of these // Store the basic problem information // -Get the number of columns, rows and rhs vector int numCols = clpSolver->getNumCols(); int numRows = clpSolver->getNumRows(); // Find the integer variables (use columnType(?)) // One if not continuous, that is binary or general integer) // columnType() = 0 continuous // = 1 binary // = 2 general integer bool * varClassInt = new bool[numCols]; const char* columnType = clpSolver->columnType(); int numGenInt = 0; for (int i = 0; i < numCols; i++) { if (clpSolver->isContinuous(i)) varClassInt[i] = 0; else varClassInt[i] = 1; if (columnType[i] == 2) numGenInt++; } // Heuristic is for problems with general integer variables. // If there are none, quit. if (numGenInt++ < 1) { delete [] varClassInt ; std::cout << "Leaving the Randomized Rounding Heuristic" << std::endl; return 0; } // -Get the rows sense const char * rowSense; rowSense = clpSolver->getRowSense(); // -Get the objective coefficients double *originalObjCoeff = CoinCopyOfArray(clpSolver->getObjCoefficients(), numCols); // -Get the matrix of the problem // rlh: look at using sparse representation double ** matrix = new double * [numRows]; for (int i = 0; i < numRows; i++) { matrix[i] = new double[numCols]; for (int j = 0; j < numCols; j++) matrix[i][j] = 0; } const CoinPackedMatrix* matrixByRow = clpSolver->getMatrixByRow(); const double * matrixElements = matrixByRow->getElements(); const int * matrixIndices = matrixByRow->getIndices(); const int * matrixStarts = matrixByRow->getVectorStarts(); for (int j = 0; j < numRows; j++) { for (int i = matrixStarts[j]; i < matrixStarts[j+1]; i++) { matrix[j][matrixIndices[i]] = matrixElements[i]; } } double * newObj = new double [numCols]; srand ( static_cast<unsigned int>(time(NULL) + 1)); int randNum; // Shuffle the rows: // Put the rows in a random order // so that the optimal solution is a different corner point than the // starting point. int * index = new int [numRows]; for (int i = 0; i < numRows; i++) index[i] = i; for (int i = 0; i < numRows; i++) { int temp = index[i]; int randNumTemp = i + intRand(numRows - i); index[i] = index[randNumTemp]; index[randNumTemp] = temp; } // Start finding corner points by iteratively doing the following: // - contruct a randomly tilted objective // - solve for (int i = 0; i < numRows; i++) { // TODO: that 10,000 could be a param in the member data if (solutions.numberSolutions > 10000) break; randNum = intRand(2); for (int j = 0; j < numCols; j++) { // for row i and column j vary the coefficient "a bit" if (randNum == 1) // if the element is zero, then set the new obj // coefficient to 0.1 (i.e., round up) if (fabs(matrix[index[i]][j]) < primalTolerance) newObj[j] = 0.1; else // if the element is nonzero, then increase the new obj // coefficient "a bit" newObj[j] = matrix[index[i]][j] * 1.1; else // if randnum is 2, then // if the element is zero, then set the new obj coeffient // to NEGATIVE 0.1 (i.e., round down) if (fabs(matrix[index[i]][j]) < primalTolerance) newObj[j] = -0.1; else // if the element is nonzero, then DEcrease the new obj coeffienct "a bit" newObj[j] = matrix[index[i]][j] * 0.9; } // Use the new "tilted" objective clpSolver->setObjective(newObj); // Based on the row sense, we decide whether to max or min if (rowSense[i] == 'L') clpSolver->setObjSense(-1); else clpSolver->setObjSense(1); // Solve with primal simplex simplex->primal(1); // rlh+ll: This was the original code. But we already have the // model pointer (it's in simplex). And, calling getModelPtr() // invalidates the cached data in the OsiClpSolverInterface // object, which means our precious rowsens is lost. So let's // not use the line below... /******* clpSolver->getModelPtr()->primal(1); */ printf("---------------------------------------------------------------- %d\n", i); } // Iteratively do this process until... // either you reach the max number of corner points (aka 10K) // or all the rows have been used as an objective. // Look at solutions int numberSolutions = solutions.numberSolutions; //const char * integerInfo = simplex->integerInformation(); //const double * columnLower = simplex->columnLower(); //const double * columnUpper = simplex->columnUpper(); printf("there are %d solutions\n", numberSolutions); // Up to here we have all the corner points // Now we need to do the random walks and roundings double ** cornerPoints = new double * [numberSolutions]; for (int j = 0; j < numberSolutions; j++) cornerPoints[j] = solutions.solution[j]; bool feasibility = 1; // rlh: use some COIN max instead of 1e30 (?) double bestObj = 1e30; std::vector< std::vector <double> > feasibles; int numFeasibles = 0; // Check the feasibility of the corner points int numCornerPoints = numberSolutions; const double * rhs = clpSolver->getRightHandSide(); // rlh: row sense hasn't changed. why a fresh copy? // Delete next line. rowSense = clpSolver->getRowSense(); for (int i = 0; i < numCornerPoints; i++) { //get the objective value for this this point double objValue = 0; for (int k = 0; k < numCols; k++) objValue += cornerPoints[i][k] * originalObjCoeff[k]; if (objValue < bestObj) { // check integer feasibility feasibility = 1; for (int j = 0; j < numCols; j++) { if (varClassInt[j]) { double closest = floor(cornerPoints[i][j] + 0.5); if (fabs(cornerPoints[i][j] - closest) > primalTolerance) { feasibility = 0; break; } } } // check all constraints satisfied if (feasibility) { for (int irow = 0; irow < numRows; irow++) { double lhs = 0; for (int j = 0; j < numCols; j++) { lhs += matrix[irow][j] * cornerPoints[i][j]; } if (rowSense[irow] == 'L' && lhs > rhs[irow] + primalTolerance) { feasibility = 0; break; } if (rowSense[irow] == 'G' && lhs < rhs[irow] - primalTolerance) { feasibility = 0; break; } if (rowSense[irow] == 'E' && (lhs - rhs[irow] > primalTolerance || lhs - rhs[irow] < -primalTolerance)) { feasibility = 0; break; } } } if (feasibility) { numFeasibles++; feasibles.push_back(std::vector <double> (numCols)); for (int k = 0; k < numCols; k++) feasibles[numFeasibles-1][k] = cornerPoints[i][k]; printf("obj: %f\n", objValue); if (objValue < bestObj) bestObj = objValue; } } } int numFeasibleCorners; numFeasibleCorners = numFeasibles; //find the center of gravity of the corner points as the first random point double * rp = new double[numCols]; for (int i = 0; i < numCols; i++) { rp[i] = 0; for (int j = 0; j < numCornerPoints; j++) { rp[i] += cornerPoints[j][i]; } rp[i] = rp[i] / numCornerPoints; } //------------------------------------------- //main loop: // -generate the next random point // -round the random point // -check the feasibility of the random point //------------------------------------------- srand ( static_cast<unsigned int>(time(NULL) + 1)); int numRandomPoints = 0; while (numRandomPoints < 50000) { numRandomPoints++; //generate the next random point int randomIndex = intRand(numCornerPoints); double random = CoinDrand48(); for (int i = 0; i < numCols; i++) { rp[i] = (random * (cornerPoints[randomIndex][i] - rp[i])) + rp[i]; } //CRISP ROUNDING //round the random point just generated double * roundRp = new double[numCols]; for (int i = 0; i < numCols; i++) { roundRp[i] = rp[i]; if (varClassInt[i]) { if (rp[i] >= 0) { if (fmod(rp[i], 1) > 0.5) roundRp[i] = floor(rp[i]) + 1; else roundRp[i] = floor(rp[i]); } else { if (fabs(fmod(rp[i], 1)) > 0.5) roundRp[i] = floor(rp[i]); else roundRp[i] = floor(rp[i]) + 1; } } } //SOFT ROUNDING // Look at original files for the "how to" on soft rounding; // Soft rounding omitted here. //Check the feasibility of the rounded random point // -Check the feasibility // -Get the rows sense rowSense = clpSolver->getRowSense(); rhs = clpSolver->getRightHandSide(); //get the objective value for this feasible point double objValue = 0; for (int i = 0; i < numCols; i++) objValue += roundRp[i] * originalObjCoeff[i]; if (objValue < bestObj) { feasibility = 1; for (int i = 0; i < numRows; i++) { double lhs = 0; for (int j = 0; j < numCols; j++) { lhs += matrix[i][j] * roundRp[j]; } if (rowSense[i] == 'L' && lhs > rhs[i] + primalTolerance) { feasibility = 0; break; } if (rowSense[i] == 'G' && lhs < rhs[i] - primalTolerance) { feasibility = 0; break; } if (rowSense[i] == 'E' && (lhs - rhs[i] > primalTolerance || lhs - rhs[i] < -primalTolerance)) { feasibility = 0; break; } } if (feasibility) { printf("Feasible Found.\n"); printf("%.2f\n", CoinCpuTime() - start); numFeasibles++; feasibles.push_back(std::vector <double> (numCols)); for (int i = 0; i < numCols; i++) feasibles[numFeasibles-1][i] = roundRp[i]; printf("obj: %f\n", objValue); if (objValue < bestObj) bestObj = objValue; } } delete [] roundRp; } printf("Number of Feasible Corners: %d\n", numFeasibleCorners); printf("Number of Feasibles Found: %d\n", numFeasibles); if (numFeasibles > 0) printf("Best Objective: %f\n", bestObj); printf("time: %.2f\n", CoinCpuTime() - start); if (numFeasibles == 0) { // cleanup delete [] varClassInt; for (int i = 0; i < numRows; i++) delete matrix[i]; delete [] matrix; delete [] newObj; delete [] index; for (int i = 0; i < numberSolutions; i++) delete cornerPoints[i]; delete [] cornerPoints; delete [] rp; return 0; } // We found something better solutionValue = bestObj; for (int k = 0; k < numCols; k++) { betterSolution[k] = feasibles[numFeasibles-1][k]; } delete [] varClassInt; for (int i = 0; i < numRows; i++) delete matrix[i]; delete [] matrix; delete [] newObj; delete [] index; for (int i = 0; i < numberSolutions; i++) delete cornerPoints[i]; delete [] cornerPoints; delete [] rp; std::cout << "Leaving the Randomized Rounding Heuristic" << std::endl; return 1; }
int main (int argc, const char *argv[]) { // Define your favorite OsiSolver OsiClpSolverInterface solver1; // Read in model using argv[1] // and assert that it is a clean model std::string dirsep(1,CoinFindDirSeparator()); std::string mpsFileName; # if defined(SAMPLEDIR) mpsFileName = SAMPLEDIR ; mpsFileName += dirsep+"p0033.mps"; # else if (argc < 2) { fprintf(stderr, "Do not know where to find sample MPS files.\n"); exit(1); } # endif if (argc>=2) mpsFileName = argv[1]; int numMpsReadErrors = solver1.readMps(mpsFileName.c_str(),""); if( numMpsReadErrors != 0 ) { printf("%d errors reading MPS file\n", numMpsReadErrors); return numMpsReadErrors; } double time1 = CoinCpuTime(); /* Options are: preprocess to do preprocessing time in minutes if 2 parameters and numeric taken as time */ bool preProcess=false; double minutes=-1.0; int nGoodParam=0; for (int iParam=2; iParam<argc;iParam++) { if (!strcmp(argv[iParam],"preprocess")) { preProcess=true; nGoodParam++; } else if (!strcmp(argv[iParam],"time")) { if (iParam+1<argc&&isdigit(argv[iParam+1][0])) { minutes=atof(argv[iParam+1]); if (minutes>=0.0) { nGoodParam+=2; iParam++; // skip time } } } } if (nGoodParam==0&&argc==3&&isdigit(argv[2][0])) { // If time is given then stop after that number of minutes minutes = atof(argv[2]); if (minutes>=0.0) nGoodParam=1; } if (nGoodParam!=argc-2&&argc>=2) { printf("Usage <file> [preprocess] [time <minutes>] or <file> <minutes>\n"); exit(1); } solver1.initialSolve(); // Reduce printout solver1.setHintParam(OsiDoReducePrint,true,OsiHintTry); // See if we want preprocessing OsiSolverInterface * solver2=&solver1; #if PREPROCESS==1 CglPreProcess process; if (preProcess) { /* Do not try and produce equality cliques and do up to 5 passes */ solver2 = process.preProcess(solver1,false,5); if (!solver2) { printf("Pre-processing says infeasible\n"); exit(2); } solver2->resolve(); } #endif CbcModel model(*solver2); model.solver()->setHintParam(OsiDoReducePrint,true,OsiHintTry); // Set up some cut generators and defaults // Probing first as gets tight bounds on continuous CglProbing generator1; generator1.setUsingObjective(true); generator1.setMaxPass(1); generator1.setMaxPassRoot(5); // Number of unsatisfied variables to look at generator1.setMaxProbe(10); generator1.setMaxProbeRoot(1000); // How far to follow the consequences generator1.setMaxLook(50); generator1.setMaxLookRoot(500); // Only look at rows with fewer than this number of elements generator1.setMaxElements(200); generator1.setRowCuts(3); CglGomory generator2; // try larger limit generator2.setLimit(300); CglKnapsackCover generator3; CglRedSplit generator4; // try larger limit generator4.setLimit(200); CglClique generator5; generator5.setStarCliqueReport(false); generator5.setRowCliqueReport(false); CglMixedIntegerRounding2 mixedGen; CglFlowCover flowGen; // Add in generators // Experiment with -1 and -99 etc model.addCutGenerator(&generator1,-1,"Probing"); model.addCutGenerator(&generator2,-1,"Gomory"); model.addCutGenerator(&generator3,-1,"Knapsack"); // model.addCutGenerator(&generator4,-1,"RedSplit"); model.addCutGenerator(&generator5,-1,"Clique"); model.addCutGenerator(&flowGen,-1,"FlowCover"); model.addCutGenerator(&mixedGen,-1,"MixedIntegerRounding"); // Say we want timings int numberGenerators = model.numberCutGenerators(); int iGenerator; for (iGenerator=0;iGenerator<numberGenerators;iGenerator++) { CbcCutGenerator * generator = model.cutGenerator(iGenerator); generator->setTiming(true); } OsiClpSolverInterface * osiclp = dynamic_cast< OsiClpSolverInterface*> (model.solver()); // go faster stripes if (osiclp) { // Turn this off if you get problems // Used to be automatically set osiclp->setSpecialOptions(128); if(osiclp->getNumRows()<300&&osiclp->getNumCols()<500) { //osiclp->setupForRepeatedUse(2,0); osiclp->setupForRepeatedUse(0,0); } } // Uncommenting this should switch off all CBC messages // model.messagesPointer()->setDetailMessages(10,10000,NULL); // Allow rounding heuristic CbcRounding heuristic1(model); model.addHeuristic(&heuristic1); // And local search when new solution found CbcHeuristicLocal heuristic2(model); model.addHeuristic(&heuristic2); // Redundant definition of default branching (as Default == User) CbcBranchUserDecision branch; model.setBranchingMethod(&branch); // Definition of node choice CbcCompareUser compare; model.setNodeComparison(compare); // Do initial solve to continuous model.initialSolve(); // Could tune more double objValue = model.solver()->getObjSense()*model.solver()->getObjValue(); double minimumDropA=CoinMin(1.0,fabs(objValue)*1.0e-3+1.0e-4); double minimumDrop= fabs(objValue)*1.0e-4+1.0e-4; printf("min drop %g (A %g)\n",minimumDrop,minimumDropA); model.setMinimumDrop(minimumDrop); if (model.getNumCols()<500) model.setMaximumCutPassesAtRoot(-100); // always do 100 if possible else if (model.getNumCols()<5000) model.setMaximumCutPassesAtRoot(100); // use minimum drop else model.setMaximumCutPassesAtRoot(20); model.setMaximumCutPasses(10); //model.setMaximumCutPasses(2); // Switch off strong branching if wanted // model.setNumberStrong(0); // Do more strong branching if small if (model.getNumCols()<5000) model.setNumberStrong(10); model.setNumberStrong(20); //model.setNumberStrong(5); model.setNumberBeforeTrust(5); model.solver()->setIntParam(OsiMaxNumIterationHotStart,100); // If time is given then stop after that number of minutes if (minutes>=0.0) { std::cout<<"Stopping after "<<minutes<<" minutes"<<std::endl; model.setDblParam(CbcModel::CbcMaximumSeconds,60.0*minutes); } // Switch off most output if (model.getNumCols()<3000) { model.messageHandler()->setLogLevel(1); //model.solver()->messageHandler()->setLogLevel(0); } else { model.messageHandler()->setLogLevel(2); model.solver()->messageHandler()->setLogLevel(1); } //model.messageHandler()->setLogLevel(2); //model.solver()->messageHandler()->setLogLevel(2); //model.setPrintFrequency(50); //#define DEBUG_CUTS #ifdef DEBUG_CUTS // Set up debugger by name (only if no preprocesing) if (!preProcess) { std::string problemName ; model.solver()->getStrParam(OsiProbName,problemName) ; model.solver()->activateRowCutDebugger(problemName.c_str()) ; } #endif #if PREPROCESS==2 // Default strategy will leave cut generators as they exist already // so cutsOnlyAtRoot (1) ignored // numberStrong (2) is 5 (default) // numberBeforeTrust (3) is 5 (default is 0) // printLevel (4) defaults (0) CbcStrategyDefault strategy(true,5,5); // Set up pre-processing to find sos if wanted if (preProcess) strategy.setupPreProcessing(2); model.setStrategy(strategy); #endif // Do complete search model.branchAndBound(); std::cout<<mpsFileName<<" took "<<CoinCpuTime()-time1<<" seconds, " <<model.getNodeCount()<<" nodes with objective " <<model.getObjValue() <<(!model.status() ? " Finished" : " Not finished") <<std::endl; // Print more statistics std::cout<<"Cuts at root node changed objective from "<<model.getContinuousObjective() <<" to "<<model.rootObjectiveAfterCuts()<<std::endl; for (iGenerator=0;iGenerator<numberGenerators;iGenerator++) { CbcCutGenerator * generator = model.cutGenerator(iGenerator); std::cout<<generator->cutGeneratorName()<<" was tried " <<generator->numberTimesEntered()<<" times and created " <<generator->numberCutsInTotal()<<" cuts of which " <<generator->numberCutsActive()<<" were active after adding rounds of cuts"; if (generator->timing()) std::cout<<" ( "<<generator->timeInCutGenerator()<<" seconds)"<<std::endl; else std::cout<<std::endl; } // Print solution if finished - we can't get names from Osi! - so get from OsiClp if (model.getMinimizationObjValue()<1.0e50) { #if PREPROCESS==1 // post process OsiSolverInterface * solver; if (preProcess) { process.postProcess(*model.solver()); // Solution now back in solver1 solver = & solver1; } else { solver = model.solver(); } #else OsiSolverInterface * solver = model.solver(); #endif int numberColumns = solver->getNumCols(); const double * solution = solver->getColSolution(); // Get names from solver1 (as OsiSolverInterface may lose) std::vector<std::string> columnNames = *solver1.getModelPtr()->columnNames(); int iColumn; std::cout<<std::setiosflags(std::ios::fixed|std::ios::showpoint)<<std::setw(14); std::cout<<"--------------------------------------"<<std::endl; for (iColumn=0;iColumn<numberColumns;iColumn++) { double value=solution[iColumn]; if (fabs(value)>1.0e-7&&solver->isInteger(iColumn)) std::cout<<std::setw(6)<<iColumn<<" " <<columnNames[iColumn]<<" " <<value<<std::endl; } std::cout<<"--------------------------------------"<<std::endl; std::cout<<std::resetiosflags(std::ios::fixed|std::ios::showpoint|std::ios::scientific); } return 0; }
int main (int argc, const char *argv[]) { /* Define your favorite OsiSolver. CbcModel clones the solver so use solver1 up to the time you pass it to CbcModel then use a pointer to cloned solver (model.solver()) */ OsiClpSolverInterface solver1; /* From now on we can build model in a solver independent way. You can add rows one at a time but for large problems this is slow so this example uses CoinBuild or CoinModel */ OsiSolverInterface * solver = &solver1; // Data (is exmip1.mps in Mps/Sample // Objective double objValue[]={1.0,2.0,0.0,0.0,0.0,0.0,0.0,-1.0}; // Lower bounds for columns double columnLower[]={2.5,0.0,0.0,0.0,0.5,0.0,0.0,0.0}; // Upper bounds for columns double columnUpper[]={COIN_DBL_MAX,4.1,1.0,1.0,4.0, COIN_DBL_MAX,COIN_DBL_MAX,4.3}; // Lower bounds for row activities double rowLower[]={2.5,-COIN_DBL_MAX,-COIN_DBL_MAX,1.8,3.0}; // Upper bounds for row activities double rowUpper[]={COIN_DBL_MAX,2.1,4.0,5.0,15.0}; // Matrix stored packed int column[] = {0,1,3,4,7, 1,2, 2,5, 3,6, 4,7}; double element[] = {3.0,1.0,-2.0,-1.0,-1.0, 2.0,1.1, 1.0,1.0, 2.8,-1.2, 1.0,1.9}; int starts[]={0,5,7,9,11,13}; // Integer variables (note upper bound already 1.0) int whichInt[]={2,3}; int numberRows=(int) (sizeof(rowLower)/sizeof(double)); int numberColumns=(int) (sizeof(columnLower)/sizeof(double)); #define BUILD 2 #if BUILD==1 // Using CoinBuild // First do columns (objective and bounds) int i; // We are not adding elements for (i=0;i<numberColumns;i++) { solver->addCol(0,NULL,NULL,columnLower[i],columnUpper[i], objValue[i]); } // mark as integer for (i=0;i<(int) (sizeof(whichInt)/sizeof(int));i++) solver->setInteger(whichInt[i]); // Now build rows CoinBuild build; for (i=0;i<numberRows;i++) { int startRow = starts[i]; int numberInRow = starts[i+1]-starts[i]; build.addRow(numberInRow,column+startRow,element+startRow, rowLower[i],rowUpper[i]); } // add rows into solver solver->addRows(build); #else /* using CoinModel - more flexible but still beta. Can do exactly same way but can mix and match much more. Also all operations are on building object */ CoinModel build; // First do columns (objective and bounds) int i; for (i=0;i<numberColumns;i++) { build.setColumnBounds(i,columnLower[i],columnUpper[i]); build.setObjective(i,objValue[i]); } // mark as integer for (i=0;i<(int) (sizeof(whichInt)/sizeof(int));i++) build.setInteger(whichInt[i]); // Now build rows for (i=0;i<numberRows;i++) { int startRow = starts[i]; int numberInRow = starts[i+1]-starts[i]; build.addRow(numberInRow,column+startRow,element+startRow, rowLower[i],rowUpper[i]); } // add rows into solver solver->loadFromCoinModel(build); #endif // Pass to solver CbcModel model(*solver); model.solver()->setHintParam(OsiDoReducePrint,true,OsiHintTry); // Set up some cut generators and defaults // Probing first as gets tight bounds on continuous CglProbing generator1; generator1.setUsingObjective(true); generator1.setMaxPass(3); generator1.setMaxProbe(100); generator1.setMaxLook(50); generator1.setRowCuts(3); // generator1.snapshot(*model.solver()); //generator1.createCliques(*model.solver(),2,1000,true); //generator1.setMode(0); CglGomory generator2; // try larger limit generator2.setLimit(300); CglKnapsackCover generator3; CglOddHole generator4; generator4.setMinimumViolation(0.005); generator4.setMinimumViolationPer(0.00002); // try larger limit generator4.setMaximumEntries(200); CglClique generator5; generator5.setStarCliqueReport(false); generator5.setRowCliqueReport(false); CglMixedIntegerRounding mixedGen; CglFlowCover flowGen; // Add in generators model.addCutGenerator(&generator1,-1,"Probing"); model.addCutGenerator(&generator2,-1,"Gomory"); model.addCutGenerator(&generator3,-1,"Knapsack"); model.addCutGenerator(&generator4,-1,"OddHole"); model.addCutGenerator(&generator5,-1,"Clique"); model.addCutGenerator(&flowGen,-1,"FlowCover"); model.addCutGenerator(&mixedGen,-1,"MixedIntegerRounding"); OsiClpSolverInterface * osiclp = dynamic_cast< OsiClpSolverInterface*> (model.solver()); // go faster stripes if (osiclp->getNumRows()<300&&osiclp->getNumCols()<500) { osiclp->setupForRepeatedUse(2,0); printf("trying slightly less reliable but faster version (? Gomory cuts okay?)\n"); printf("may not be safe if doing cuts in tree which need accuracy (level 2 anyway)\n"); } // Allow rounding heuristic CbcRounding heuristic1(model); model.addHeuristic(&heuristic1); // And local search when new solution found CbcHeuristicLocal heuristic2(model); model.addHeuristic(&heuristic2); // Redundant definition of default branching (as Default == User) CbcBranchUserDecision branch; model.setBranchingMethod(&branch); // Definition of node choice CbcCompareUser compare; model.setNodeComparison(compare); // Do initial solve to continuous model.initialSolve(); // Could tune more model.setMinimumDrop(CoinMin(1.0, fabs(model.getMinimizationObjValue())*1.0e-3+1.0e-4)); if (model.getNumCols()<500) model.setMaximumCutPassesAtRoot(-100); // always do 100 if possible else if (model.getNumCols()<5000) model.setMaximumCutPassesAtRoot(100); // use minimum drop else model.setMaximumCutPassesAtRoot(20); //model.setMaximumCutPasses(5); // Switch off strong branching if wanted // model.setNumberStrong(0); // Do more strong branching if small if (model.getNumCols()<5000) model.setNumberStrong(10); model.solver()->setIntParam(OsiMaxNumIterationHotStart,100); // If time is given then stop after that number of minutes if (argc>2) { int minutes = atoi(argv[2]); std::cout<<"Stopping after "<<minutes<<" minutes"<<std::endl; assert (minutes>=0); model.setDblParam(CbcModel::CbcMaximumSeconds,60.0*minutes); } // Switch off most output if (model.getNumCols()<3000) { model.messageHandler()->setLogLevel(1); //model.solver()->messageHandler()->setLogLevel(0); } else { model.messageHandler()->setLogLevel(2); model.solver()->messageHandler()->setLogLevel(1); } double time1 = CoinCpuTime(); // Do complete search model.branchAndBound(); std::cout<<" Branch and cut took "<<CoinCpuTime()-time1<<" seconds, " <<model.getNodeCount()<<" nodes with objective " <<model.getObjValue() <<(!model.status() ? " Finished" : " Not finished") <<std::endl; // Print more statistics std::cout<<"Cuts at root node changed objective from "<<model.getContinuousObjective() <<" to "<<model.rootObjectiveAfterCuts()<<std::endl; int numberGenerators = model.numberCutGenerators(); for (int iGenerator=0;iGenerator<numberGenerators;iGenerator++) { CbcCutGenerator * generator = model.cutGenerator(iGenerator); std::cout<<generator->cutGeneratorName()<<" was tried " <<generator->numberTimesEntered()<<" times and created " <<generator->numberCutsInTotal()<<" cuts of which " <<generator->numberCutsActive()<<" were active after adding rounds of cuts" <<std::endl; } // Print solution if any - we can't get names from Osi! if (model.getMinimizationObjValue()<1.0e50) { int numberColumns = model.solver()->getNumCols(); const double * solution = model.solver()->getColSolution(); int iColumn; std::cout<<std::setiosflags(std::ios::fixed|std::ios::showpoint)<<std::setw(14); std::cout<<"--------------------------------------"<<std::endl; for (iColumn=0;iColumn<numberColumns;iColumn++) { double value=solution[iColumn]; if (fabs(value)>1.0e-7&&model.solver()->isInteger(iColumn)) std::cout<<std::setw(6)<<iColumn<<" "<<value<<std::endl; } std::cout<<"--------------------------------------"<<std::endl; std::cout<<std::resetiosflags(std::ios::fixed|std::ios::showpoint|std::ios::scientific); } return 0; }
int main (int argc, const char *argv[]) { // Define your favorite OsiSolver OsiClpSolverInterface solver1; // Read in model using argv[1] // and assert that it is a clean model std::string mpsFileName; #if defined(SAMPLEDIR) mpsFileName = SAMPLEDIR "/p0033.mps"; #else if (argc < 2) { fprintf(stderr, "Do not know where to find sample MPS files.\n"); exit(1); } #endif if (argc>=2) mpsFileName = argv[1]; int numMpsReadErrors = solver1.readMps(mpsFileName.c_str(),""); assert(numMpsReadErrors==0); double time1 = CoinCpuTime(); /* Options are: preprocess to do preprocessing time in minutes if 2 parameters and numeric taken as time */ bool preProcess=false; double minutes=-1.0; int nGoodParam=0; for (int iParam=2; iParam<argc;iParam++) { if (!strcmp(argv[iParam],"preprocess")) { preProcess=true; nGoodParam++; } else if (!strcmp(argv[iParam],"time")) { if (iParam+1<argc&&isdigit(argv[iParam+1][0])) { minutes=atof(argv[iParam+1]); if (minutes>=0.0) { nGoodParam+=2; iParam++; // skip time } } } } if (nGoodParam==0&&argc==3&&isdigit(argv[2][0])) { // If time is given then stop after that number of minutes minutes = atof(argv[2]); if (minutes>=0.0) nGoodParam=1; } if (nGoodParam!=argc-2&&argc>=2) { printf("Usage <file> [preprocess] [time <minutes>] or <file> <minutes>\n"); exit(1); } //solver1.getModelPtr()->setLogLevel(0); solver1.messageHandler()->setLogLevel(0); solver1.initialSolve(); // Reduce printout solver1.setHintParam(OsiDoReducePrint,true,OsiHintTry); CbcModel model(solver1); model.solver()->setHintParam(OsiDoReducePrint,true,OsiHintTry); // Set up some cut generators and defaults // Probing first as gets tight bounds on continuous CglProbing generator1; generator1.setUsingObjective(true); generator1.setMaxPass(1); generator1.setMaxPassRoot(5); // Number of unsatisfied variables to look at generator1.setMaxProbe(10); generator1.setMaxProbeRoot(1000); // How far to follow the consequences generator1.setMaxLook(50); generator1.setMaxLookRoot(500); // Only look at rows with fewer than this number of elements generator1.setMaxElements(200); generator1.setRowCuts(3); CglGomory generator2; // try larger limit generator2.setLimit(300); CglKnapsackCover generator3; CglRedSplit generator4; // try larger limit generator4.setLimit(200); CglClique generator5; generator5.setStarCliqueReport(false); generator5.setRowCliqueReport(false); CglMixedIntegerRounding2 mixedGen; CglFlowCover flowGen; // Add in generators // Experiment with -1 and -99 etc model.addCutGenerator(&generator1,-1,"Probing"); model.addCutGenerator(&generator2,-1,"Gomory"); model.addCutGenerator(&generator3,-1,"Knapsack"); // model.addCutGenerator(&generator4,-1,"RedSplit"); model.addCutGenerator(&generator5,-1,"Clique"); model.addCutGenerator(&flowGen,-1,"FlowCover"); model.addCutGenerator(&mixedGen,-1,"MixedIntegerRounding"); OsiClpSolverInterface * osiclp = dynamic_cast< OsiClpSolverInterface*> (model.solver()); // go faster stripes if (osiclp) { // Turn this off if you get problems // Used to be automatically set osiclp->setSpecialOptions(128); if(osiclp->getNumRows()<300&&osiclp->getNumCols()<500) { //osiclp->setupForRepeatedUse(2,1); osiclp->setupForRepeatedUse(0,1); } } // Uncommenting this should switch off most CBC messages //model.messagesPointer()->setDetailMessages(10,5,5000); // Allow rounding heuristic CbcRounding heuristic1(model); model.addHeuristic(&heuristic1); // And local search when new solution found CbcHeuristicLocal heuristic2(model); model.addHeuristic(&heuristic2); // Redundant definition of default branching (as Default == User) CbcBranchUserDecision branch; model.setBranchingMethod(&branch); // Definition of node choice CbcCompareUser compare; model.setNodeComparison(compare); // Do initial solve to continuous model.initialSolve(); // Could tune more double objValue = model.solver()->getObjSense()*model.solver()->getObjValue(); double minimumDropA=CoinMin(1.0,fabs(objValue)*1.0e-3+1.0e-4); double minimumDrop= fabs(objValue)*1.0e-4+1.0e-4; printf("min drop %g (A %g)\n",minimumDrop,minimumDropA); model.setMinimumDrop(minimumDrop); if (model.getNumCols()<500) model.setMaximumCutPassesAtRoot(-100); // always do 100 if possible else if (model.getNumCols()<5000) model.setMaximumCutPassesAtRoot(100); // use minimum drop else model.setMaximumCutPassesAtRoot(20); model.setMaximumCutPasses(10); //model.setMaximumCutPasses(2); // Switch off strong branching if wanted // model.setNumberStrong(0); // Do more strong branching if small if (model.getNumCols()<5000) model.setNumberStrong(10); model.setNumberStrong(20); //model.setNumberStrong(5); model.setNumberBeforeTrust(5); //model.setSizeMiniTree(2); model.solver()->setIntParam(OsiMaxNumIterationHotStart,100); // If time is given then stop after that number of minutes if (minutes>=0.0) { std::cout<<"Stopping after "<<minutes<<" minutes"<<std::endl; model.setDblParam(CbcModel::CbcMaximumSeconds,60.0*minutes); } // Switch off most output if (model.getNumCols()<3000) { model.messageHandler()->setLogLevel(1); //model.solver()->messageHandler()->setLogLevel(0); } else { model.messageHandler()->setLogLevel(2); model.solver()->messageHandler()->setLogLevel(1); } // Default strategy will leave cut generators as they exist already // so cutsOnlyAtRoot (1) ignored // numberStrong (2) is 5 (default) // numberBeforeTrust (3) is 5 (default is 0) // printLevel (4) defaults (0) CbcStrategyDefault strategy(true,5,5); // Set up pre-processing to find sos if wanted if (preProcess) strategy.setupPreProcessing(2); model.setStrategy(strategy); // Go round adding cuts to cutoff last solution // Stop after finding 20 best solutions for (int iPass=0;iPass<20;iPass++) { time1 = CoinCpuTime(); // Do complete search model.branchAndBound(); std::cout<<mpsFileName<<" took "<<CoinCpuTime()-time1<<" seconds, " <<model.getNodeCount()<<" nodes with objective " <<model.getObjValue() <<(!model.status() ? " Finished" : " Not finished") <<std::endl; // Stop if infeasible if (model.isProvenInfeasible()) break; // Print solution if finished - we can't get names from Osi! - so get from OsiClp assert (model.getMinimizationObjValue()<1.0e50); OsiSolverInterface * solver = model.solver(); int numberColumns = solver->getNumCols(); const double * solution = model.bestSolution(); //const double * lower = solver->getColLower(); //const double * upper = solver->getColUpper(); // Get names from solver1 (as OsiSolverInterface may lose) std::vector<std::string> columnNames = *solver1.getModelPtr()->columnNames(); int iColumn; std::cout<<std::setiosflags(std::ios::fixed|std::ios::showpoint)<<std::setw(14); std::cout<<"--------------------------------------"<<std::endl; for (iColumn=0;iColumn<numberColumns;iColumn++) { double value=solution[iColumn]; if (fabs(value)>1.0e-7&&solver->isInteger(iColumn)) std::cout<<std::setw(6)<<iColumn<<" " <<columnNames[iColumn]<<" " <<value //<<" "<<lower[iColumn]<<" "<<upper[iColumn] <<std::endl; } std::cout<<"--------------------------------------"<<std::endl; std::cout<<std::resetiosflags(std::ios::fixed|std::ios::showpoint|std::ios::scientific); /* Now add cut to reference copy. resetting to reference copy also gets rid of best solution so we should either save best solution, reset, add cut OR add cut to reference copy then reset - this is doing latter */ OsiSolverInterface * refSolver = model.referenceSolver(); const double * bestSolution = model.bestSolution(); const double * originalLower = refSolver->getColLower(); const double * originalUpper = refSolver->getColUpper(); CoinPackedVector cut; double rhs = 1.0; for (iColumn=0;iColumn<numberColumns;iColumn++) { double value=bestSolution[iColumn]; if (solver->isInteger(iColumn)) { // only works for 0-1 variables assert (originalLower[iColumn]==0.0&& originalUpper[iColumn]==1.0); // double check integer assert (fabs(floor(value+0.5)-value)<1.0e-5); if (value>0.5) { // at 1.0 cut.insert(iColumn,-1.0); rhs -= 1.0; } else { // at 0.0 cut.insert(iColumn,1.0); } } } // now add cut refSolver->addRow(cut,rhs,COIN_DBL_MAX); model.resetToReferenceSolver(); } return 0; }
int main (int argc, const char *argv[]) { // Define your favorite OsiSolver OsiClpSolverInterface solver1; // Read in model using argv[1] // and assert that it is a clean model std::string mpsFileName; #if defined(SAMPLEDIR) mpsFileName = SAMPLEDIR "/p0033.mps"; #else if (argc < 2) { fprintf(stderr, "Do not know where to find sample MPS files.\n"); exit(1); } #endif if (argc>=2) mpsFileName = argv[1]; int numMpsReadErrors = solver1.readMps(mpsFileName.c_str(),""); assert(numMpsReadErrors==0); double time1 = CoinCpuTime(); OsiClpSolverInterface solverSave = solver1; /* Options are: preprocess to do preprocessing time in minutes if 2 parameters and numeric taken as time */ bool preProcess=false; double minutes=-1.0; int nGoodParam=0; for (int iParam=2; iParam<argc;iParam++) { if (!strcmp(argv[iParam],"preprocess")) { preProcess=true; nGoodParam++; } else if (!strcmp(argv[iParam],"time")) { if (iParam+1<argc&&isdigit(argv[iParam+1][0])) { minutes=atof(argv[iParam+1]); if (minutes>=0.0) { nGoodParam+=2; iParam++; // skip time } } } } if (nGoodParam==0&&argc==3&&isdigit(argv[2][0])) { // If time is given then stop after that number of minutes minutes = atof(argv[2]); if (minutes>=0.0) nGoodParam=1; } if (nGoodParam!=argc-2&&argc>=2) { printf("Usage <file> [preprocess] [time <minutes>] or <file> <minutes>\n"); exit(1); } // Reduce printout solver1.setHintParam(OsiDoReducePrint,true,OsiHintTry); // See if we want preprocessing OsiSolverInterface * solver2=&solver1; CglPreProcess process; // Never do preprocessing until dual tests out as can fix incorrectly preProcess=false; if (preProcess) { /* Do not try and produce equality cliques and do up to 5 passes */ solver2 = process.preProcess(solver1,false,5); if (!solver2) { printf("Pre-processing says infeasible\n"); exit(2); } solver2->resolve(); } // Turn L rows into cuts CglStoredUser stored; { int numberRows = solver2->getNumRows(); int * whichRow = new int[numberRows]; // get row copy const CoinPackedMatrix * rowCopy = solver2->getMatrixByRow(); const int * column = rowCopy->getIndices(); const int * rowLength = rowCopy->getVectorLengths(); const CoinBigIndex * rowStart = rowCopy->getVectorStarts(); const double * rowLower = solver2->getRowLower(); const double * rowUpper = solver2->getRowUpper(); const double * element = rowCopy->getElements(); int iRow,nDelete=0; for (iRow=0;iRow<numberRows;iRow++) { if (rowLower[iRow]<-1.0e20||rowUpper[iRow]>1.0e20) { // take out whichRow[nDelete++]=iRow; } } // leave some rows to avoid empty problem (Gomory does not like) nDelete = CoinMax(CoinMin(nDelete,numberRows-5),0); for (int jRow=0;jRow<nDelete;jRow++) { iRow=whichRow[jRow]; int start = rowStart[iRow]; stored.addCut(rowLower[iRow],rowUpper[iRow],rowLength[iRow], column+start,element+start); } /* The following is problem specific. Normally cuts are deleted if slack on cut basic. On some problems you may wish to leave cuts in as long as slack value zero */ int numberCuts=stored.sizeRowCuts(); for (int iCut=0;iCut<numberCuts;iCut++) { //stored.mutableRowCutPointer(iCut)->setEffectiveness(1.0e50); } solver2->deleteRows(nDelete,whichRow); delete [] whichRow; } CbcModel model(*solver2); model.solver()->setHintParam(OsiDoReducePrint,true,OsiHintTry); // Set up some cut generators and defaults // Probing first as gets tight bounds on continuous CglProbing generator1; generator1.setUsingObjective(true); generator1.setMaxPass(1); generator1.setMaxPassRoot(5); // Number of unsatisfied variables to look at generator1.setMaxProbe(10); generator1.setMaxProbeRoot(1000); // How far to follow the consequences generator1.setMaxLook(50); generator1.setMaxLookRoot(500); // Only look at rows with fewer than this number of elements generator1.setMaxElements(200); generator1.setRowCuts(3); CglGomory generator2; // try larger limit generator2.setLimit(300); CglKnapsackCover generator3; CglRedSplit generator4; // try larger limit generator4.setLimit(200); CglClique generator5; generator5.setStarCliqueReport(false); generator5.setRowCliqueReport(false); CglMixedIntegerRounding2 mixedGen; CglFlowCover flowGen; // Add in generators // Experiment with -1 and -99 etc // This is just for one particular model model.addCutGenerator(&generator1,-1,"Probing"); //model.addCutGenerator(&generator2,-1,"Gomory"); model.addCutGenerator(&generator2,1,"Gomory"); model.addCutGenerator(&generator3,-1,"Knapsack"); // model.addCutGenerator(&generator4,-1,"RedSplit"); //model.addCutGenerator(&generator5,-1,"Clique"); model.addCutGenerator(&generator5,1,"Clique"); model.addCutGenerator(&flowGen,-1,"FlowCover"); model.addCutGenerator(&mixedGen,-1,"MixedIntegerRounding"); // Add stored cuts (making sure at all depths) model.addCutGenerator(&stored,1,"Stored",true,false,false,-100,1,-1); int numberGenerators = model.numberCutGenerators(); int iGenerator; // Say we want timings for (iGenerator=0;iGenerator<numberGenerators;iGenerator++) { CbcCutGenerator * generator = model.cutGenerator(iGenerator); generator->setTiming(true); } OsiClpSolverInterface * osiclp = dynamic_cast< OsiClpSolverInterface*> (model.solver()); // go faster stripes if (osiclp) { if(osiclp->getNumRows()<300&&osiclp->getNumCols()<500) { //osiclp->setupForRepeatedUse(2,0); osiclp->setupForRepeatedUse(0,0); } // Don't allow dual stuff osiclp->setSpecialOptions(osiclp->specialOptions()|262144); } // Uncommenting this should switch off all CBC messages // model.messagesPointer()->setDetailMessages(10,10000,NULL); // No heuristics // Do initial solve to continuous model.initialSolve(); /* You need the next few lines - a) so that cut generator will always be called again if it generated cuts b) it is known that matrix is not enough to define problem so do cuts even if it looks integer feasible at continuous optimum. c) a solution found by strong branching will be ignored. d) don't recompute a solution once found */ // Make sure cut generator called correctly (a) iGenerator=numberGenerators-1; model.cutGenerator(iGenerator)->setMustCallAgain(true); // Say cuts needed at continuous (b) OsiBabSolver oddCuts; oddCuts.setSolverType(4); // owing to bug must set after initialSolve model.passInSolverCharacteristics(&oddCuts); // Say no to all solutions by strong branching (c) CbcFeasibilityNoStrong noStrong; model.setProblemFeasibility(noStrong); // Say don't recompute solution d) model.setSpecialOptions(4); // Could tune more double objValue = model.solver()->getObjSense()*model.solver()->getObjValue(); double minimumDropA=CoinMin(1.0,fabs(objValue)*1.0e-3+1.0e-4); double minimumDrop= fabs(objValue)*1.0e-4+1.0e-4; printf("min drop %g (A %g)\n",minimumDrop,minimumDropA); model.setMinimumDrop(minimumDrop); if (model.getNumCols()<500) model.setMaximumCutPassesAtRoot(-100); // always do 100 if possible else if (model.getNumCols()<5000) model.setMaximumCutPassesAtRoot(100); // use minimum drop else model.setMaximumCutPassesAtRoot(20); model.setMaximumCutPasses(10); //model.setMaximumCutPasses(2); // Switch off strong branching if wanted // model.setNumberStrong(0); // Do more strong branching if small if (model.getNumCols()<5000) model.setNumberStrong(10); model.setNumberStrong(20); //model.setNumberStrong(5); model.setNumberBeforeTrust(5); model.solver()->setIntParam(OsiMaxNumIterationHotStart,100); // If time is given then stop after that number of minutes if (minutes>=0.0) { std::cout<<"Stopping after "<<minutes<<" minutes"<<std::endl; model.setDblParam(CbcModel::CbcMaximumSeconds,60.0*minutes); } // Switch off most output if (model.getNumCols()<30000) { model.messageHandler()->setLogLevel(1); //model.solver()->messageHandler()->setLogLevel(0); } else { model.messageHandler()->setLogLevel(2); model.solver()->messageHandler()->setLogLevel(1); } //model.messageHandler()->setLogLevel(2); //model.solver()->messageHandler()->setLogLevel(2); //model.setPrintFrequency(50); //#define DEBUG_CUTS #ifdef DEBUG_CUTS // Set up debugger by name (only if no preprocesing) if (!preProcess) { std::string problemName ; model.solver()->getStrParam(OsiProbName,problemName) ; model.solver()->activateRowCutDebugger(problemName.c_str()) ; } #endif // Do complete search model.branchAndBound(); std::cout<<mpsFileName<<" took "<<CoinCpuTime()-time1<<" seconds, " <<model.getNodeCount()<<" nodes with objective " <<model.getObjValue() <<(!model.status() ? " Finished" : " Not finished") <<std::endl; // Print more statistics std::cout<<"Cuts at root node changed objective from "<<model.getContinuousObjective() <<" to "<<model.rootObjectiveAfterCuts()<<std::endl; for (iGenerator=0;iGenerator<numberGenerators;iGenerator++) { CbcCutGenerator * generator = model.cutGenerator(iGenerator); std::cout<<generator->cutGeneratorName()<<" was tried " <<generator->numberTimesEntered()<<" times and created " <<generator->numberCutsInTotal()<<" cuts of which " <<generator->numberCutsActive()<<" were active after adding rounds of cuts"; if (generator->timing()) std::cout<<" ( "<<generator->timeInCutGenerator()<<" seconds)"<<std::endl; else std::cout<<std::endl; } // Print solution if finished - we can't get names from Osi! - so get from OsiClp if (model.getMinimizationObjValue()<1.0e50) { // post process OsiSolverInterface * solver; if (preProcess) { process.postProcess(*model.solver()); // Solution now back in solver1 solver = & solver1; } else { solver = model.solver(); } int numberColumns = solver->getNumCols(); const double * solution = solver->getColSolution(); // Get names from solver1 (as OsiSolverInterface may lose) std::vector<std::string> columnNames = *solver1.getModelPtr()->columnNames(); int iColumn; std::cout<<std::setiosflags(std::ios::fixed|std::ios::showpoint)<<std::setw(14); std::cout<<"--------------------------------------"<<std::endl; for (iColumn=0;iColumn<numberColumns;iColumn++) { double value=solution[iColumn]; if (fabs(value)>1.0e-7&&solver->isInteger(iColumn)) { std::cout<<std::setw(6)<<iColumn<<" " <<columnNames[iColumn]<<" " <<value<<std::endl; solverSave.setColLower(iColumn,value); solverSave.setColUpper(iColumn,value); } } std::cout<<"--------------------------------------"<<std::endl; std::cout<<std::resetiosflags(std::ios::fixed|std::ios::showpoint|std::ios::scientific); solverSave.initialSolve(); } return 0; }