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 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. 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(); 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; }