int main (int argc, const char *argv[]) { // Define a Solver which inherits from OsiClpsolverInterface -> OsiSolverInterface ClpQuadInterface solver1; // Read in model using argv[1] if (argc <= 1) { printf("using %s <modelfile>\n", argv[0]); return 1; } // must use clp to get a quadratic model ClpSimplex * clp = solver1.getModelPtr(); int numMpsReadErrors = clp->readMps(argv[1]); // and assert that it is a clean model if( numMpsReadErrors != 0 ) { printf("%d errors reading MPS file\n", numMpsReadErrors); return numMpsReadErrors; } // This clones solver CbcModel model(solver1); // But now model doesn't know about integers! const char * integerInfo = clp->integerInformation(); int numberColumns = clp->numberColumns(); // and point to solver OsiSolverInterface * solver2 = model.solver(); for (int iColumn=0;iColumn<numberColumns;iColumn++) { if (integerInfo[iColumn]) solver2->setInteger(iColumn); } // Okay - now we have a good MIQP solver // Within branch and cut it is better (at present) to switch off all objectives ClpQuadInterface * osiclp = dynamic_cast< ClpQuadInterface*> (solver2); assert (osiclp); // Set fake objective so Cbc not confused osiclp->initialize(); solver2->setHintParam(OsiDoReducePrint,true,OsiHintTry); // Set up some cut generators and defaults // Probing first as gets tight bounds on continuous CglProbing generator1; // can not use objective generator1.setUsingObjective(false); generator1.setMaxPass(3); generator1.setMaxProbe(100); generator1.setMaxLook(50); generator1.setRowCuts(3); // Add in generators // Only some generators work (and even then try without first) model.addCutGenerator(&generator1,1,"Probing"); // Allow rounding heuristic CbcRounding heuristic1(model); // do not add yet as don't know how to deal with quadratic objective //model.addHeuristic(&heuristic1); // Redundant definition of default branching (as Default == User) CbcBranchUserDecision branch; model.setBranchingMethod(&branch); // Definition of node choice CbcCompareUser compare; // breadth first //compare.setWeight(0.0); 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)); model.setMaximumCutPassesAtRoot(0); model.setMaximumCutPasses(0); // Switch off strong branching if wanted //model.setNumberStrong(5); model.solver()->setIntParam(OsiMaxNumIterationHotStart,10000); // 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); } model.setPrintFrequency(50); double time1 = CoinCpuTime(); // Do complete search model.branchAndBound(); std::cout<<argv[1]<<" 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 finished - we can't get names from Osi! if (!model.status()&&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 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; }
/** Perform a branch-and-bound on given setup.*/ void CouenneBab::branchAndBound (Bonmin::BabSetupBase & s) { double remaining_time = s.getDoubleParameter(Bonmin::BabSetupBase::MaxTime) + CoinCpuTime(); /* Put a link to this into solver.*/ OsiBabSolver * babInfo = dynamic_cast<OsiBabSolver *>(s.continuousSolver()->getAuxiliaryInfo()); assert(babInfo); Bonmin::BabInfo * bonBabInfoPtr = dynamic_cast<Bonmin::BabInfo*>(babInfo); if (bonBabInfoPtr == NULL) { //Replace with a Bonmin::babInfo bonBabInfoPtr = new Bonmin::BabInfo(*babInfo); s.continuousSolver()->setAuxiliaryInfo(bonBabInfoPtr); delete bonBabInfoPtr; bonBabInfoPtr = dynamic_cast<Bonmin::BabInfo*>(s.continuousSolver()->getAuxiliaryInfo()); } bonBabInfoPtr->setBabPtr(this); s.nonlinearSolver()->solver()->setup_global_time_limit(s.getDoubleParameter(Bonmin::BabSetupBase::MaxTime)); OsiSolverInterface * solver = s.continuousSolver()->clone(); delete modelHandler_; modelHandler_ = s.continuousSolver()->messageHandler()->clone(); model_.passInMessageHandler(modelHandler_); model_.assignSolver(solver, true); // s.continuousSolver() = model_.solver(); // if(s.continuousSolver()->objects()!=NULL){ // model_.addObjects(s.continuousSolver()->numberObjects(),s.continuousSolver()->objects()); // } int specOpt = s.getIntParameter(Bonmin::BabSetupBase::SpecialOption); if (specOpt) { model_.setSpecialOptions(specOpt); if (specOpt==16) { Bonmin::CbcNlpStrategy strat(s.getIntParameter(Bonmin::BabSetupBase::MaxFailures), s.getIntParameter(Bonmin::BabSetupBase::MaxInfeasible), s.getIntParameter(Bonmin::BabSetupBase::FailureBehavior)); model_.setStrategy(strat); } } model_.setMaximumCutPasses(s.getIntParameter(Bonmin::BabSetupBase::NumCutPasses)); model_.setMaximumCutPassesAtRoot(s.getIntParameter(Bonmin::BabSetupBase::NumCutPassesAtRoot)); //Setup cutting plane methods for (Bonmin::BabSetupBase::CuttingMethods::iterator i = s.cutGenerators().begin() ; i != s.cutGenerators().end() ; i++) { Bonmin::OaDecompositionBase * oa = dynamic_cast<Bonmin::OaDecompositionBase *>(i->cgl); if (oa && oa->reassignLpsolver()) oa->assignLpInterface(model_.solver()); model_.addCutGenerator(i->cgl,i->frequency,i->id.c_str(), i->normal, i->atSolution); if(i->always){ model_.cutGenerators()[model_.numberCutGenerators()-1] ->setMustCallAgain(true); } } for (Bonmin::BabSetupBase::HeuristicMethods::iterator i = s.heuristics().begin() ; i != s.heuristics().end() ; i++) { CbcHeuristic * heu = i->heuristic; heu->setModel(&model_); model_.addHeuristic(heu, i->id.c_str()); } //need to record solver logLevel here int logLevel = s.continuousSolver()->messageHandler()->logLevel(); //Set true branch-and-bound parameters model_.setLogLevel(s.getIntParameter(Bonmin::BabSetupBase::BabLogLevel)); // Put back solver logLevel model_.solver()->messageHandler()->setLogLevel(logLevel); model_.setPrintFrequency(s.getIntParameter(Bonmin::BabSetupBase::BabLogInterval)); bool ChangedObject = false; //Pass over user set branching priorities to Cbc if (s.continuousSolver()->objects()==NULL) { //assert (s.branchingMethod() == NULL); const OsiTMINLPInterface * nlpSolver = s.nonlinearSolver(); //set priorities, prefered directions... const int * priorities = nlpSolver->getPriorities(); const double * upPsCosts = nlpSolver->getUpPsCosts(); const double * downPsCosts = nlpSolver->getDownPsCosts(); const int * directions = nlpSolver->getBranchingDirections(); bool hasPseudo = (upPsCosts!=NULL); model_.findIntegers(true,hasPseudo); OsiObject ** simpleIntegerObjects = model_.objects(); int numberObjects = model_.numberObjects(); if (priorities != NULL || directions != NULL || hasPseudo) { ChangedObject = true; for (int i = 0 ; i < numberObjects ; i++) { CbcObject * object = dynamic_cast<CbcObject *> (simpleIntegerObjects[i]); int iCol = object->columnNumber(); if (priorities) object->setPriority(priorities[iCol]); if (directions) object->setPreferredWay(directions[iCol]); if (upPsCosts) { CbcSimpleIntegerPseudoCost * pscObject = dynamic_cast<CbcSimpleIntegerPseudoCost*> (object); pscObject->setUpPseudoCost(upPsCosts[iCol]); pscObject->setDownPseudoCost(downPsCosts[iCol]); } } } #if 1 // Now pass user set Sos constraints (code inspired from CoinSolve.cpp) const TMINLP::SosInfo * sos = s.nonlinearSolver()->model()->sosConstraints(); if (!s.getIntParameter(Bonmin::BabSetupBase::DisableSos) && sos && sos->num > 0) { // we have some sos constraints const OsiTMINLPInterface * nlpSolver = s.nonlinearSolver(); const int & numSos = sos->num; (*nlpSolver->messageHandler())<<"Adding "<<sos->num<<" sos constraints." <<CoinMessageEol; CbcObject ** objects = new CbcObject*[numSos]; const int * starts = sos->starts; const int * indices = sos->indices; const char * types = sos->types; const double * weights = sos->weights; //verify if model has user set priorities bool hasPriorities = false; const int * varPriorities = nlpSolver->getPriorities(); int numberObjects = model_.numberObjects(); if (varPriorities) { for (int i = 0 ; i < numberObjects ; i++) { if (varPriorities[i]) { hasPriorities = true; break; } } } const int * sosPriorities = sos->priorities; if (sosPriorities) { for (int i = 0 ; i < numSos ; i++) { if (sosPriorities[i]) { hasPriorities = true; break; } } } for (int i = 0 ; i < numSos ; i++) { int start = starts[i]; int length = starts[i + 1] - start; #ifdef DO_IT_NWAY printf("setting nway object\n"), objects[i] = new CbcNWay(&model_, length, &indices[start], i); objects[i]->setPriority(1); #else objects[i] = new CbcSOS(&model_, length, &indices[start], &weights[start], i, types[i]); objects[i]->setPriority(10); #endif if (hasPriorities && sosPriorities && sosPriorities[i]) { objects[i]->setPriority(sosPriorities[i]); } } model_.addObjects (numSos, objects); for (int i = 0 ; i < numSos ; i++) delete objects[i]; delete [] objects; } #endif //If Setup contains more objects add them to Cbc if (s.objects().size()) { CbcObject ** objects = new CbcObject *[s.objects().size()]; for (unsigned int i = 0 ; i < s.objects().size() ; i++) { objects[i] = dynamic_cast<CbcObject *> (s.objects()[i]); assert(objects[i]); objects[i]->setModel(&model_); } model_.addObjects ((int) s.objects().size(), objects); delete [] objects; } replaceIntegers(model_.objects(), model_.numberObjects()); } else { // Pass in objects to Cbc // Redundant definition of default branching (as Default == User) assert (s.branchingMethod() != NULL); // Add nonlinear and integer objects (need to add OsiSOS) model_.addObjects (s.continuousSolver () -> numberObjects (), s.continuousSolver () -> objects ()); // Now model_ has only CouenneObjects and SOS objects // for (int i=0; i<nco; i++) // if (!(dynamic_cast <CbcSimpleInteger *> (s.continuousSolver () -> objects () [i]))) // model_ . objects () [nRealObj++] = s.continuousSolver () -> objects () [i] -> clone (); CbcBranchDefaultDecision branch; s.branchingMethod()->setSolver(model_.solver()); BonChooseVariable * strong2 = dynamic_cast<BonChooseVariable *>(s.branchingMethod()); if (strong2) strong2->setCbcModel(&model_); branch.setChooseMethod(*s.branchingMethod()); model_.setBranchingMethod(&branch); // prevent duplicating object when copying in CbcModel.cpp model_.solver()->deleteObjects(); } model_.setDblParam(CbcModel::CbcCutoffIncrement, s.getDoubleParameter(Bonmin::BabSetupBase::CutoffDecr)); model_.setCutoff(s.getDoubleParameter(Bonmin::BabSetupBase::Cutoff) + CUTOFF_TOL); model_.setDblParam(CbcModel::CbcAllowableGap, s.getDoubleParameter(Bonmin::BabSetupBase::AllowableGap)); model_.setDblParam(CbcModel::CbcAllowableFractionGap, s.getDoubleParameter(Bonmin::BabSetupBase::AllowableFractionGap)); // Definition of node selection strategy if (s.nodeComparisonMethod()==Bonmin::BabSetupBase::bestBound) { CbcCompareObjective compare; model_.setNodeComparison(compare); } else if (s.nodeComparisonMethod()==Bonmin::BabSetupBase::DFS) { CbcCompareDepth compare; model_.setNodeComparison(compare); } else if (s.nodeComparisonMethod()==Bonmin::BabSetupBase::BFS) { CbcCompareDefault compare; compare.setWeight(0.0); model_.setNodeComparison(compare); } else if (s.nodeComparisonMethod()==Bonmin::BabSetupBase::dynamic) { CbcCompareDefault compare; model_.setNodeComparison(compare); } else if (s.nodeComparisonMethod()==Bonmin::BabSetupBase::bestGuess) { // Right now, this is a mess. We need a separation of the // pseudo costs from the ChooseVariable method CbcCompareEstimate compare; model_.setNodeComparison(compare); GuessHeuristic * guessHeu = new GuessHeuristic(model_); model_.addHeuristic(guessHeu); delete guessHeu; } if (s.treeTraversalMethod() == Bonmin::BabSetupBase::HeapOnly) { //Do nothing this is the default of Cbc. } else if (s.treeTraversalMethod() == Bonmin::BabSetupBase::DiveFromBest) { CbcDiver treeTraversal; treeTraversal.initialize(s); model_.passInTreeHandler(treeTraversal); } else if (s.treeTraversalMethod() == Bonmin::BabSetupBase::ProbedDive) { CbcProbedDiver treeTraversal; treeTraversal.initialize(s); model_.passInTreeHandler(treeTraversal); } else if (s.treeTraversalMethod() == Bonmin::BabSetupBase::DfsDiveFromBest) { CbcDfsDiver treeTraversal; treeTraversal.initialize(s); model_.passInTreeHandler(treeTraversal); } else if (s.treeTraversalMethod() == Bonmin::BabSetupBase::DfsDiveDynamic) { CbcDfsDiver treeTraversal; treeTraversal.initialize(s); model_.passInTreeHandler(treeTraversal); DiverCompare compare; compare.setComparisonDive(*model_.nodeComparison()); compare.setComparisonBound(CbcCompareObjective()); CbcDfsDiver * dfs = dynamic_cast<CbcDfsDiver *> (model_.tree()); assert(dfs); compare.setDiver(dfs); model_.setNodeComparison(compare); } model_.setNumberStrong(s.getIntParameter(Bonmin::BabSetupBase::NumberStrong)); model_.setNumberBeforeTrust(s.getIntParameter(Bonmin::BabSetupBase::MinReliability)); model_.setNumberPenalties(8); model_.setDblParam(CbcModel::CbcMaximumSeconds, s.getDoubleParameter(Bonmin::BabSetupBase::MaxTime)); model_.setMaximumNodes(s.getIntParameter(Bonmin::BabSetupBase::MaxNodes)); model_.setMaximumNumberIterations(s.getIntParameter(Bonmin::BabSetupBase::MaxIterations)); model_.setMaximumSolutions(s.getIntParameter(Bonmin::BabSetupBase::MaxSolutions)); model_.setIntegerTolerance(s.getDoubleParameter(Bonmin::BabSetupBase::IntTol)); //Get objects from model_ if it is not null means there are some sos constraints or non-integer branching object // pass them to cut generators. OsiObject ** objects = model_.objects(); if (specOpt!=16 && objects) { int numberObjects = model_.numberObjects(); if (objects_ != NULL) { for (int i = 0 ; i < nObjects_; i++) delete objects_[i]; } delete [] objects_; objects_ = new OsiObject*[numberObjects]; nObjects_ = numberObjects; for (int i = 0 ; i < numberObjects; i++) { OsiObject * obj = objects[i]; CbcSimpleInteger * intObj = dynamic_cast<CbcSimpleInteger *> (obj); if (intObj) { objects_[i] = intObj->osiObject(); } else { CbcSOS * sosObj = dynamic_cast<CbcSOS *>(obj); if (sosObj) objects_[i] = sosObj->osiObject(model_.solver()); else {//Maybe an unsupported CbcObject CbcObject * cbcObj = dynamic_cast<CbcObject *>(obj); if (cbcObj) { std::cerr<<"Unsupported CbcObject appears in the code"<<std::endl; throw UNSUPPORTED_CBC_OBJECT; } else {//It has to be an OsiObject. objects_[i]=obj->clone(); } } } } CbcCutGenerator ** gen = model_.cutGenerators(); int numGen = model_.numberCutGenerators(); for (int i = 0 ; i < numGen ; i++) { Bonmin::OaDecompositionBase * oa = dynamic_cast<Bonmin::OaDecompositionBase * >(gen[i]->generator()); // if (oa) // printf ("\n\n\nat least one OADecompBase\n\n\n"); if (oa) // pass objects oa->setObjects(objects_,nObjects_); } } // if (objects_) { // for (int i = 0 ; i < nObjects_; i++) // delete objects_ [i]; // delete [] objects_; // } // OsiObject ** objects = model_.objects(); // int numObjects = model_.numberObjects(); // nObjects_ = 0; // objects_ = new OsiObject* [numObjects]; // for (int i=0; i < numObjects; ++i) // if (objects [i]) // objects_ [nObjects_++] = objects [i] -> clone (); try { //Get the time and start. { OsiTMINLPInterface * tmpOsi = NULL; if(s.nonlinearSolver() == s.continuousSolver()){ tmpOsi = dynamic_cast<OsiTMINLPInterface *> (model_.solver()); tmpOsi->forceSolverOutput(s.getIntParameter(Bonmin::BabSetupBase::RootLogLevel)); } model_.initialSolve(); if(tmpOsi != NULL){ tmpOsi->setSolverOutputToDefault(); } } int ival; s.options()->GetEnumValue("enable_dynamic_nlp", ival, "bonmin."); if(s.nonlinearSolver() == s.continuousSolver() && ival) { if(!model_.solver()->isProvenOptimal() ){//Something went wrong check if objective is linear and alternate model // can be solved OsiTMINLPInterface * tmpOsi = dynamic_cast<OsiTMINLPInterface *> (model_.solver()); TMINLPLinObj * tmp_tminlp = dynamic_cast<TMINLPLinObj *> (tmpOsi->model()); tmpOsi->setModel(tmp_tminlp->tminlp()); model_.initialSolve(); } else { LinearCutsGenerator cgl; cgl.initialize(s); OsiCuts cuts; cgl.generateCuts(*model_.solver(), cuts); std::vector<const OsiRowCut *> mycuts(cuts.sizeRowCuts()); for(int i = 0 ; i < cuts.sizeRowCuts() ; i++){ mycuts[i] = cuts.rowCutPtr(i); } model_. solver () -> applyRowCuts ((int) mycuts.size(), (const OsiRowCut **) &mycuts[0]); } //Added by Claudia OsiTMINLPInterface * nlpSolver = dynamic_cast<OsiTMINLPInterface *>(model_.solver()); if(nlpSolver && nlpSolver->getNewCutoffDecr()!=COIN_DBL_MAX) model_.setDblParam(CbcModel::CbcCutoffIncrement, nlpSolver->getNewCutoffDecr()); model_.solver()->resolve(); } // for Couenne model_.passInSolverCharacteristics (bonBabInfoPtr); continuousRelaxation_ =model_.solver()->getObjValue(); if (specOpt==16)//Set warm start point for Ipopt { #if 1 const double * colsol = model_.solver()->getColSolution(); const double * duals = model_.solver()->getRowPrice(); OsiTMINLPInterface * tnlpSolver = dynamic_cast<OsiTMINLPInterface *>(model_.solver()); // Primal dual point is not copied if one (supposedly a better one) has already been put into the solver. if(tnlpSolver->problem()->has_x_init() != 2){ model_.solver()->setColSolution(colsol); model_.solver()->setRowPrice(duals); } #else OsiTMINLPInterface * tnlpSolver = dynamic_cast<OsiTMINLPInterface *>(model_.solver()); CoinWarmStart * warm = tnlpSolver->solver()->getWarmStart(tnlpSolver->problem()); tnlpSolver->solver()->setWarmStart(warm, tnlpSolver->problem()); delete warm; #endif #if 0 // Sometimes primal dual point is problematic in the context of Cut-and-branch model_.solver()->resolve(); if(!model_.solver()->isProvenOptimal()) model_.solver()->setColSolution(NULL); #endif } #ifdef SIGNAL CoinSighandler_t saveSignal = SIG_DFL; // register signal handler saveSignal = signal (SIGINT,couenne_signal_handler); currentBranchModel = &model_; #endif // to get node parent info in Cbc, pass parameter 3. //model_.branchAndBound(3); remaining_time -= CoinCpuTime(); model_.setDblParam(CbcModel::CbcMaximumSeconds, remaining_time); if(remaining_time > 0.) model_.branchAndBound(); } catch(TNLPSolver::UnsolvedError *E){ s.nonlinearSolver()->model()->finalize_solution (TMINLP::MINLP_ERROR, 0, NULL, DBL_MAX); throw E; } numNodes_ = model_.getNodeCount(); bestObj_ = model_.getObjValue(); bestBound_ = model_.getBestPossibleObjValue(); mipIterationCount_ = model_.getIterationCount(); bool hasFailed = false; if (specOpt==16)//Did we continue branching on a failure { CbcNlpStrategy * nlpStrategy = dynamic_cast<CbcNlpStrategy *>(model_.strategy()); if (nlpStrategy) hasFailed = nlpStrategy->hasFailed(); else throw -1; } else hasFailed = s.nonlinearSolver()->hasContinuedOnAFailure(); // Output summarizing cut generators (taken from CbcSolver.cpp) // ToDo put into proper print level int numberGenerators = model_.numberCutGenerators(); for (int iGenerator=0;iGenerator<numberGenerators;iGenerator++) { CbcCutGenerator * generator = model_.cutGenerator(iGenerator); //CglStored * stored = dynamic_cast<CglStored*>(generator->generator()); if (true&&!(generator->numberCutsInTotal() || generator->numberColumnCuts())) continue; if(modelHandler_->logLevel() >= 1) { *modelHandler_ << generator->cutGeneratorName() << "was tried" << generator->numberTimesEntered() << "times and created" << generator->numberCutsInTotal()+generator->numberColumnCuts() << "cuts of which" << generator->numberCutsActive() << "were active after adding rounds of cuts"; // if (generator->timing()) { // char timebuf[20]; // sprintf(timebuf, "(%.3fs)", generator->timeInCutGenerator()); // *modelHandler_ << timebuf << CoinMessageEol; // } // else { // *modelHandler_ << CoinMessageEol; // } } } TMINLP::SolverReturn status = TMINLP::MINLP_ERROR; if (model_.numberObjects()==0) { if (bestSolution_) delete [] bestSolution_; OsiSolverInterface * solver = (s.nonlinearSolver() == s.continuousSolver())? model_.solver() : s.nonlinearSolver(); bestSolution_ = new double[solver->getNumCols()]; CoinCopyN(solver->getColSolution(), solver->getNumCols(), bestSolution_); bestObj_ = bestBound_ = solver->getObjValue(); } if (bonBabInfoPtr->bestSolution2().size() > 0) { assert((int) bonBabInfoPtr->bestSolution2().size() == s.nonlinearSolver()->getNumCols()); if (bestSolution_) delete [] bestSolution_; bestSolution_ = new double[s.nonlinearSolver()->getNumCols()]; std::copy(bonBabInfoPtr->bestSolution2().begin(), bonBabInfoPtr->bestSolution2().end(), bestSolution_); bestObj_ = (bonBabInfoPtr->bestObj2()); (*s.nonlinearSolver()->messageHandler())<<"\nReal objective function: " <<bestObj_<<CoinMessageEol; } else if (model_.bestSolution()) { if (bestSolution_) delete [] bestSolution_; bestSolution_ = new double[s.nonlinearSolver()->getNumCols()]; CoinCopyN(model_.bestSolution(), s.nonlinearSolver()->getNumCols(), bestSolution_); } if(remaining_time <= 0.){ status = TMINLP::LIMIT_EXCEEDED; if (bestSolution_) { mipStatus_ = Feasible; } else { mipStatus_ = NoSolutionKnown; } } else if (model_.status() == 0) { if(model_.isContinuousUnbounded()){ status = TMINLP::CONTINUOUS_UNBOUNDED; mipStatus_ = UnboundedOrInfeasible; } else if (bestSolution_) { status = TMINLP::SUCCESS; mipStatus_ = FeasibleOptimal; } else { status = TMINLP::INFEASIBLE; mipStatus_ = ProvenInfeasible; } } else if (model_.status() == 1 || model_.status() == 5) { #if (BONMIN_VERSION_MAJOR > 1) || (BONMIN_VERSION_MINOR > 6) status = model_.status() == 1 ? TMINLP::LIMIT_EXCEEDED : TMINLP::USER_INTERRUPT; #else status = TMINLP::LIMIT_EXCEEDED; #endif if (bestSolution_) { mipStatus_ = Feasible; } else { mipStatus_ = NoSolutionKnown; } } else if (model_.status()==2) { status = TMINLP::MINLP_ERROR; } // Which solution should we use? false if RBS's, true if Cbc's bool use_RBS_Cbc = !problem_ || !(problem_ -> getRecordBestSol ()) || !(problem_ -> getRecordBestSol () -> getHasSol()) || (((fabs (bestObj_) < COUENNE_INFINITY / 1e4) && (problem_ -> getRecordBestSol () -> getVal () > bestObj_))); /* if we do not pass the cbc solution and problem_ -> getRecordBestSol () -> getHasSol() is true, then there should be a solution vector in problem_ -> getRecordBestSol () */ assert(use_RBS_Cbc || problem_ -> getRecordBestSol () -> getSol() != NULL); s.nonlinearSolver () -> model () -> finalize_solution (status, s.nonlinearSolver () -> getNumCols (), use_RBS_Cbc ? bestSolution_ : problem_ -> getRecordBestSol () -> getSol (), use_RBS_Cbc ? bestObj_ : problem_ -> getRecordBestSol () -> getVal ()); }
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[]) { // Get data std::string fileName = "./sudoku_sample.csv"; if (argc>=2) fileName = argv[1]; FILE * fp = fopen(fileName.c_str(),"r"); if (!fp) { printf("Unable to open file %s\n",fileName.c_str()); exit(0); } #define MAX_SIZE 16 int valueOffset=1; double lo[MAX_SIZE*MAX_SIZE],up[MAX_SIZE*MAX_SIZE]; char line[80]; int row,column; /*************************************** Read .csv file and see if 9 or 16 Su Doku ***************************************/ int size=9; for (row=0;row<size;row++) { fgets(line,80,fp); // Get size of sudoku puzzle (9 or 16) if (!row) { int get=0; size=1; while (line[get]>=32) { if (line[get]==',') size++; get++; } assert (size==9||size==16); printf("Solving Su Doku of size %d\n",size); if (size==16) valueOffset=0; } int get=0; for (column=0;column<size;column++) { lo[size*row+column]=valueOffset; up[size*row+column]=valueOffset-1+size; if (line[get]!=','&&line[get]>=32) { // skip blanks if (line[get]==' ') { get++; continue; } int value = line[get]-'0'; if (size==9) { assert (value>=1&&value<=9); } else { assert (size==16); if (value<0||value>9) { if (line[get]=='"') { get++; value = 10 + line[get]-'A'; if (value<10||value>15) { value = 10 + line[get]-'a'; } get++; } else { value = 10 + line[get]-'A'; if (value<10||value>15) { value = 10 + line[get]-'a'; } } } assert (value>=0&&value<=15); } lo[size*row+column]=value; up[size*row+column]=value; get++; } get++; } } int block_size = (int) sqrt ((double) size); /*************************************** Now build rules for all different 3*9 or 3*16 sets of variables Number variables by row*size+column ***************************************/ int starts[3*MAX_SIZE+1]; int which[3*MAX_SIZE*MAX_SIZE]; int put=0; int set=0; starts[0]=0; // By row for (row=0;row<size;row++) { for (column=0;column<size;column++) which[put++]=row*size+column; starts[set+1]=put; set++; } // By column for (column=0;column<size;column++) { for (row=0;row<size;row++) which[put++]=row*size+column; starts[set+1]=put; set++; } // By box for (row=0;row<size;row+=block_size) { for (column=0;column<size;column+=block_size) { for (int row2=row;row2<row+block_size;row2++) { for (int column2=column;column2<column+block_size;column2++) which[put++]=row2*size+column2; } starts[set+1]=put; set++; } } OsiClpSolverInterface solver1; /*************************************** Create model Set variables to be general integer variables although priorities probably mean that it won't matter ***************************************/ CoinModel build; // Columns char name[4]; for (row=0;row<size;row++) { for (column=0;column<size;column++) { if (row<10) { if (column<10) sprintf(name,"X%d%d",row,column); else sprintf(name,"X%d%c",row,'A'+(column-10)); } else { if (column<10) sprintf(name,"X%c%d",'A'+(row-10),column); else sprintf(name,"X%c%c",'A'+(row-10),'A'+(column-10)); } double value = CoinDrand48()*100.0; build.addColumn(0,NULL,NULL,lo[size*row+column], up[size*row+column], value, name,true); } } /*************************************** Now add in extra variables for N way branching ***************************************/ for (row=0;row<size;row++) { for (column=0;column<size;column++) { int iColumn = size*row+column; double value = lo[iColumn]; if (value<up[iColumn]) { for (int i=0;i<size;i++) build.addColumn(0,NULL,NULL,0.0,1.0,0.0); } else { // fixed // obviously could do better if we missed out variables int which = ((int) value) - valueOffset; for (int i=0;i<size;i++) { if (i!=which) build.addColumn(0,NULL,NULL,0.0,0.0,0.0); else build.addColumn(0,NULL,NULL,0.0,1.0,0.0); } } } } /*************************************** Now rows ***************************************/ double values[]={1.0,1.0,1.0,1.0, 1.0,1.0,1.0,1.0, 1.0,1.0,1.0,1.0, 1.0,1.0,1.0,1.0}; int indices[MAX_SIZE+1]; double rhs = size==9 ? 45.0 : 120.0; for (row=0;row<3*size;row++) { int iStart = starts[row]; for (column=0;column<size;column++) indices[column]=which[column+iStart]; build.addRow(size,indices,values,rhs,rhs); } double values2[MAX_SIZE+1]; values2[0]=-1.0; for (row=0;row<size;row++) values2[row+1]=row+valueOffset; // Now add rows for extra variables for (row=0;row<size;row++) { for (column=0;column<size;column++) { int iColumn = row*size+column; int base = size*size + iColumn*size; indices[0]=iColumn; for (int i=0;i<size;i++) indices[i+1]=base+i; build.addRow(size+1,indices,values2,0.0,0.0); } } solver1.loadFromCoinModel(build); build.writeMps("xx.mps"); double time1 = CoinCpuTime(); solver1.initialSolve(); CbcModel model(solver1); model.solver()->setHintParam(OsiDoReducePrint,true,OsiHintTry); model.solver()->setHintParam(OsiDoScale,false,OsiHintTry); /*************************************** Add in All different cut generator and All different branching So we will have integers then cut branching then N way branching in reverse priority order ***************************************/ // Cut generator CglAllDifferent allDifferent(3*size,starts,which); model.addCutGenerator(&allDifferent,-99,"allDifferent"); model.cutGenerator(0)->setWhatDepth(5); CbcObject ** objects = new CbcObject * [4*size*size]; int nObj=0; for (row=0;row<3*size;row++) { int iStart = starts[row]; objects[row]= new CbcBranchAllDifferent(&model,size,which+iStart); objects[row]->setPriority(2000+nObj); // do after rest satisfied nObj++; } /*************************************** Add in N way branching and while we are at it add in cuts ***************************************/ CglStored stored; for (row=0;row<size;row++) { for (column=0;column<size;column++) { int iColumn = row*size+column; int base = size*size + iColumn*size; int i; for ( i=0;i<size;i++) indices[i]=base+i; CbcNWay * obj = new CbcNWay(&model,size,indices,nObj); int seq[200]; int newUpper[200]; memset(newUpper,0,sizeof(newUpper)); for (i=0;i<size;i++) { int state=9999; int one=1; int nFix=1; // Fix real variable seq[0]=iColumn; newUpper[0]=valueOffset+i; int kColumn = base+i; int j; // same row for (j=0;j<size;j++) { int jColumn = row*size+j; int jjColumn = size*size+jColumn*size+i; if (jjColumn!=kColumn) { seq[nFix++]=jjColumn; // must be zero } } // same column for (j=0;j<size;j++) { int jColumn = j*size+column; int jjColumn = size*size+jColumn*size+i; if (jjColumn!=kColumn) { seq[nFix++]=jjColumn; // must be zero } } // same block int kRow = row/block_size; kRow *= block_size; int kCol = column/block_size; kCol *= block_size; for (j=kRow;j<kRow+block_size;j++) { for (int jc=kCol;jc<kCol+block_size;jc++) { int jColumn = j*size+jc; int jjColumn = size*size+jColumn*size+i; if (jjColumn!=kColumn) { seq[nFix++]=jjColumn; // must be zero } } } // seem to need following? const int * upperAddress = newUpper; const int * seqAddress = seq; CbcFixVariable fix(1,&state,&one,&upperAddress,&seqAddress,&nFix,&upperAddress,&seqAddress); obj->setConsequence(indices[i],fix); // Now do as cuts for (int kk=1;kk<nFix;kk++) { int jColumn = seq[kk]; int cutInd[2]; cutInd[0]=kColumn; if (jColumn>kColumn) { cutInd[1]=jColumn; stored.addCut(-COIN_DBL_MAX,1.0,2,cutInd,values); } } } objects[nObj]= obj; objects[nObj]->setPriority(nObj); nObj++; } } model.addObjects(nObj,objects); for (row=0;row<nObj;row++) delete objects[row]; delete [] objects; model.messageHandler()->setLogLevel(1); model.addCutGenerator(&stored,1,"stored"); // Say we want timings int numberGenerators = model.numberCutGenerators(); int iGenerator; for (iGenerator=0;iGenerator<numberGenerators;iGenerator++) { CbcCutGenerator * generator = model.cutGenerator(iGenerator); generator->setTiming(true); } // Set this to get all solutions (all ones in newspapers should only have one) //model.setCutoffIncrement(-1.0e6); /*************************************** Do branch and bound ***************************************/ // Do complete search model.branchAndBound(); std::cout<<"took "<<CoinCpuTime()-time1<<" seconds, " <<model.getNodeCount()<<" nodes with objective " <<model.getObjValue() <<(!model.status() ? " Finished" : " Not finished") <<std::endl; /*************************************** Print solution and check it is feasible We could modify output so could be imported by spreadsheet ***************************************/ if (model.getMinimizationObjValue()<1.0e50) { const double * solution = model.bestSolution(); int put=0; for (row=0;row<size;row++) { for (column=0;column<size;column++) { int value = (int) floor(solution[row*size+column]+0.5); assert (value>=lo[put]&&value<=up[put]); // save for later test lo[put++]=value; printf("%d ",value); } printf("\n"); } // check valid bool valid=true; // By row for (row=0;row<size;row++) { put=0; for (column=0;column<size;column++) which[put++]=row*size+column; assert (put==size); int i; for (i=0;i<put;i++) which[i]=(int) lo[which[i]]; std::sort(which,which+put); int last = valueOffset-1; for (i=0;i<put;i++) { int value=which[i]; if (value!=last+1) valid=false; last=value; } } // By column for (column=0;column<size;column++) { put=0; for (row=0;row<size;row++) which[put++]=row*size+column; assert (put==size); int i; for (i=0;i<put;i++) which[i]=(int) lo[which[i]]; std::sort(which,which+put); int last = valueOffset-1; for (i=0;i<put;i++) { int value=which[i]; if (value!=last+1) valid=false; last=value; } } // By box for (row=0;row<size;row+=block_size) { for (column=0;column<size;column+=block_size) { put=0; for (int row2=row;row2<row+block_size;row2++) { for (int column2=column;column2<column+block_size;column2++) which[put++]=row2*size+column2; } assert (put==size); int i; for (i=0;i<put;i++) which[i]=(int) lo[which[i]]; std::sort(which,which+put); int last = valueOffset-1; for (i=0;i<put;i++) { int value=which[i]; if (value!=last+1) valid=false; last=value; } } } if (valid) { printf("solution is valid\n"); } else { printf("solution is not valid\n"); abort(); } } 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; }
int main (int argc, const char *argv[]) { CbcSolver3 solver1; // Read in model using argv[1] // and assert that it is a clean model std::string mpsFileName; 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) { printf("Usage <file> [preprocess] [time <minutes>] or <file> <minutes>\n"); exit(1); } solver1.initialSolve(); // Reduce printout solver1.setHintParam(OsiDoReducePrint,true,OsiHintTry); // Say we want scaling //solver1.setHintParam(OsiDoScale,true,OsiHintTry); //solver1.setCleanupScaling(1); // See if we want preprocessing OsiSolverInterface * solver2=&solver1; 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(); } CbcModel model(*solver2); // Point to solver OsiSolverInterface * solver3 = model.solver(); CbcSolver3 * osiclp = dynamic_cast< CbcSolver3*> (solver3); assert (osiclp); const double fractionFix=0.985; osiclp->initialize(&model,NULL); osiclp->setAlgorithm(2); osiclp->setMemory(1000); osiclp->setNested(fractionFix); //osiclp->setNested(1.0); //off // Set up some cut generators and defaults // Probing first as gets tight bounds on continuous CglProbing generator1; generator1.setUsingObjective(true); generator1.setMaxPass(3); // Number of unsatisfied variables to look at generator1.setMaxProbe(10); // How far to follow the consequences generator1.setMaxLook(50); // 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; 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; /* This is same as default constructor - (1,true,1) I presume if maxAggregate larger then slower but maybe better criterion can be 1 through 3 Reference: Hugues Marchand and Laurence A. Wolsey Aggregation and Mixed Integer Rounding to Solve MIPs Operations Research, 49(3), May-June 2001. */ int maxAggregate=1; bool multiply=true; int criterion=1; CglMixedIntegerRounding2 mixedGen2(maxAggregate,multiply,criterion); CglFlowCover flowGen; // Add in generators // Experiment with -1 and -99 etc model.addCutGenerator(&generator1,-99,"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"); //model.addCutGenerator(&mixedGen2,-1,"MixedIntegerRounding2"); // Say we want timings int numberGenerators = model.numberCutGenerators(); int iGenerator; for (iGenerator=0;iGenerator<numberGenerators;iGenerator++) { CbcCutGenerator * generator = model.cutGenerator(iGenerator); generator->setTiming(true); } // Allow rounding heuristic CbcRounding heuristic1(model); model.addHeuristic(&heuristic1); // And Greedy heuristic CbcHeuristicGreedyCover heuristic2(model); // Use original upper and perturb more heuristic2.setAlgorithm(11); 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); int iColumn; int numberColumns = solver3->getNumCols(); // do pseudo costs CbcObject ** objects = new CbcObject * [numberColumns+1]; const CoinPackedMatrix * matrix = solver3->getMatrixByCol(); // Column copy const int * columnLength = matrix->getVectorLengths(); const double * objective = model.getObjCoefficients(); int n=0; for (iColumn=0;iColumn<numberColumns;iColumn++) { if (solver3->isInteger(iColumn)) { double costPer = objective[iColumn]/ ((double) columnLength[iColumn]); CbcSimpleIntegerPseudoCost * newObject = new CbcSimpleIntegerPseudoCost(&model,n,iColumn, costPer,costPer); newObject->setMethod(3); objects[n++]= newObject; } } // and special fix lots branch objects[n++]=new CbcBranchToFixLots(&model,-1.0e-6,fractionFix+0.01,1,0,NULL); model.addObjects(n,objects); for (iColumn=0;iColumn<n;iColumn++) delete objects[iColumn]; delete [] objects; // High priority for odd object int followPriority=1; model.passInPriorities(&followPriority,true); // 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(1); // Do more strong branching if small //if (model.getNumCols()<5000) //model.setNumberStrong(10); // Switch off strong branching if wanted model.setNumberStrong(0); 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()<300000) { 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()) ; model.solver()->activateRowCutDebugger("cap6000a") ; } #endif // Do complete search try { model.branchAndBound(); } catch (CoinError e) { e.print(); if (e.lineNumber()>=0) std::cout<<"This was from a CoinAssert"<<std::endl; exit(0); } //void printHowMany(); //printHowMany(); 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! if (model.getMinimizationObjValue()<1.0e50) { // post process if (preProcess) process.postProcess(*model.solver()); 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 doBaCParam (CoinParam *param) { assert (param != 0) ; CbcGenParam *genParam = dynamic_cast<CbcGenParam *>(param) ; assert (genParam != 0) ; CbcGenCtlBlk *ctlBlk = genParam->obj() ; assert (ctlBlk != 0) ; CbcModel *model = ctlBlk->model_ ; assert (model != 0) ; /* Setup to return nonfatal/fatal error (1/-1) by default. */ int retval ; if (CoinParamUtils::isInteractive()) { retval = 1 ; } else { retval = -1 ; } ctlBlk->setBaBStatus(CbcGenCtlBlk::BACAbandon, CbcGenCtlBlk::BACmInvalid, CbcGenCtlBlk::BACwNotStarted, false, 0) ; /* We ain't gonna do squat without a good model. */ if (!ctlBlk->goodModel_) { std::cout << "** Current model not valid!" << std::endl ; return (retval) ; } /* Start the clock ticking. */ double time1 = CoinCpuTime() ; double time2 ; /* Create a clone of the model which we can modify with impunity. Extract the underlying solver for convenient access. */ CbcModel babModel(*model) ; OsiSolverInterface *babSolver = babModel.solver() ; assert (babSolver != 0) ; # if CBC_TRACK_SOLVERS > 0 std::cout << "doBaCParam: initial babSolver is " << std::hex << babSolver << std::dec << ", log level " << babSolver->messageHandler()->logLevel() << "." << std::endl ; # endif /* Solve the root relaxation. Bail unless it solves to optimality. */ if (!solveRelaxation(&babModel)) { ctlBlk->setBaBStatus(&babModel, CbcGenCtlBlk::BACwBareRoot) ; return (0) ; } # if COIN_CBC_VERBOSITY > 0 std::cout << "doBaCParam: initial relaxation z = " << babSolver->getObjValue() << "." << std::endl ; # endif /* Are we up for fixing variables based on reduced cost alone? */ if (ctlBlk->djFix_.action_ == true) { reducedCostHack(babSolver, ctlBlk->djFix_.threshold_) ; } /* Time to consider preprocessing. We'll do a bit of setup before getting to the meat of the issue. preIppSolver will hold a clone of the unpreprocessed constraint system. We'll need it when we postprocess. ippSolver holds the preprocessed constraint system. Again, we clone it and give the clone to babModel for B&C. Presumably we need an unmodified copy of the preprocessed system to do postprocessing, but the copy itself is hidden inside the preprocess object. */ OsiSolverInterface *preIppSolver = 0 ; CglPreProcess ippObj ; bool didIPP = false ; int numberChanged = 0 ; int numberOriginalColumns = babSolver->getNumCols() ; CbcGenCtlBlk::IPPControl ippAction = ctlBlk->getIPPAction() ; if (!(ippAction == CbcGenCtlBlk::IPPOff || ippAction == CbcGenCtlBlk::IPPStrategy)) { double timeLeft = babModel.getMaximumSeconds() ; preIppSolver = babSolver->clone() ; OsiSolverInterface *ippSolver ; # if CBC_TRACK_SOLVERS > 0 std::cout << "doBaCParam: clone made prior to IPP is " << std::hex << preIppSolver << std::dec << ", log level " << preIppSolver->messageHandler()->logLevel() << "." << std::endl ; # endif preIppSolver->setHintParam(OsiDoInBranchAndCut, true, OsiHintDo) ; ippObj.messageHandler()->setLogLevel(babModel.logLevel()) ; CglProbing probingGen ; probingGen.setUsingObjective(true) ; probingGen.setMaxPass(3) ; probingGen.setMaxProbeRoot(preIppSolver->getNumCols()) ; probingGen.setMaxElements(100) ; probingGen.setMaxLookRoot(50) ; probingGen.setRowCuts(3) ; ippObj.addCutGenerator(&probingGen) ; /* For preProcessNonDefault, the 2nd parameter controls the conversion of clique and SOS constraints. 0 does nothing, -1 converts <= to ==, and 2 and 3 form SOS sets under strict and not-so-strict conditions, respectively. */ int convert = 0 ; if (ippAction == CbcGenCtlBlk::IPPEqual) { convert = -1 ; } else if (ippAction == CbcGenCtlBlk::IPPEqualAll) { convert = -2 ; } else if (ippAction == CbcGenCtlBlk::IPPSOS) { convert = 2 ; } else if (ippAction == CbcGenCtlBlk::IPPTrySOS) { convert = 3 ; } ippSolver = ippObj.preProcessNonDefault(*preIppSolver, convert, 10) ; # if CBC_TRACK_SOLVERS > 0 std::cout << "doBaCParam: solver returned from IPP is " << std::hex << ippSolver << std::dec ; if (ippSolver) { std::cout << ", log level " << ippSolver->messageHandler()->logLevel() ; } std::cout << "." << std::endl ; # endif /* ippSolver == 0 is success of a sort --- integer preprocess has found the problem to be infeasible or unbounded. Need to think about how to indicate status. */ if (!ippSolver) { std::cout << "Integer preprocess says infeasible or unbounded" << std::endl ; delete preIppSolver ; ctlBlk->setBaBStatus(&babModel, CbcGenCtlBlk::BACwIPP) ; return (0) ; } # if COIN_CBC_VERBOSITY > 0 else { std::cout << "After integer preprocessing, model has " << ippSolver->getNumRows() << " rows, " << ippSolver->getNumCols() << " columns, and " << ippSolver->getNumElements() << " elements." << std::endl ; } # endif preIppSolver->setHintParam(OsiDoInBranchAndCut, false, OsiHintDo) ; ippSolver->setHintParam(OsiDoInBranchAndCut, false, OsiHintDo) ; if (ippAction == CbcGenCtlBlk::IPPSave) { ippSolver->writeMps("presolved", "mps", 1.0) ; std::cout << "Integer preprocessed model written to `presolved.mps' " << "as minimisation problem." << std::endl ; } OsiSolverInterface *osiTmp = ippSolver->clone() ; babModel.assignSolver(osiTmp) ; babSolver = babModel.solver() ; # if CBC_TRACK_SOLVERS > 0 std::cout << "doBaCParam: clone of IPP solver passed to babModel is " << std::hex << babSolver << std::dec << ", log level " << babSolver->messageHandler()->logLevel() << "." << std::endl ; # endif if (!solveRelaxation(&babModel)) { delete preIppSolver ; ctlBlk->setBaBStatus(&babModel, CbcGenCtlBlk::BACwIPPRelax) ; return (0) ; } # if COIN_CBC_VERBOSITY > 0 std::cout << "doBaCParam: presolved relaxation z = " << babSolver->getObjValue() << "." << std::endl ; # endif babModel.setMaximumSeconds(timeLeft - (CoinCpuTime() - time1)) ; didIPP = true ; } /* At this point, babModel and babSolver hold the constraint system we'll use for B&C (either the original system or the preprocessed system) and we have a solution to the lp relaxation. If we're using the COSTSTRATEGY option, set up priorities here and pass them to the babModel. */ if (ctlBlk->priorityAction_ != CbcGenCtlBlk::BPOff) { setupPriorities(&babModel, ctlBlk->priorityAction_) ; } /* Install heuristics and cutting planes. */ installHeuristics(ctlBlk, &babModel) ; installCutGenerators(ctlBlk, &babModel) ; /* Set up status print frequency for babModel. */ if (babModel.getNumCols() > 2000 || babModel.getNumRows() > 1500 || babModel.messageHandler()->logLevel() > 1) babModel.setPrintFrequency(100) ; /* If we've read in a known good solution for debugging, activate the row cut debugger. */ if (ctlBlk->debugSol_.values_) { if (ctlBlk->debugSol_.numCols_ == babModel.getNumCols()) { babSolver->activateRowCutDebugger(ctlBlk->debugSol_.values_) ; } else { std::cout << "doBaCParam: debug file has incorrect number of columns." << std::endl ; } } /* Set ratio-based integrality gap, if specified by user. */ if (ctlBlk->setByUser_[CbcCbcParam::GAPRATIO] == true) { double obj = babSolver->getObjValue() ; double gapRatio = babModel.getDblParam(CbcModel::CbcAllowableFractionGap) ; double gap = gapRatio * (1.0e-5 + fabs(obj)) ; babModel.setAllowableGap(gap) ; std::cout << "doBaCParam: Continuous objective = " << obj << ", so allowable gap set to " << gap << std::endl ; } /* A bit of mystery code. As best I can figure, setSpecialOptions(2) suppresses the removal of warm start information when checkSolution runs an lp to check a solution. John's comment, ``probably faster to use a basis to get integer solutions'' makes some sense in this context. Didn't try to track down moreMipOptions just yet. */ babModel.setSpecialOptions(babModel.specialOptions() | 2) ; /* { int ndx = whichParam(MOREMIPOPTIONS,numberParameters,parameters) ; int moreMipOptions = parameters[ndx].intValue() ; if (moreMipOptions >= 0) { printf("more mip options %d\n",moreMipOptions); babModel.setSearchStrategy(moreMipOptions); } } */ /* Begin the final run-up to branch-and-cut. Make sure that objects are set up in the solver. It's possible that whoever loaded the model into the solver also set up objects. But it's also entirely likely that none exist to this point (and interesting to note that IPP doesn't need to know anything about objects). */ setupObjects(babSolver, didIPP, &ippObj) ; /* Set the branching method. We can't do this until we establish objects, because the constructor will set up arrays based on the number of objects, and there's no provision to set this information after creation. Arguably not good --- it'd be nice to set this in the prototype model that's cloned for this routine. In CoinSolve, shadowPriceMode is handled with the TESTOSI option. */ OsiChooseStrong strong(babSolver) ; strong.setNumberBeforeTrusted(babModel.numberBeforeTrust()) ; strong.setNumberStrong(babModel.numberStrong()) ; strong.setShadowPriceMode(ctlBlk->chooseStrong_.shadowPriceMode_) ; CbcBranchDefaultDecision decision ; decision.setChooseMethod(strong) ; babModel.setBranchingMethod(decision) ; /* Here I've deleted a huge block of code that deals with external priorities, branch direction, pseudocosts, and solution. (PRIORITYIN) Also a block of code that generates C++ code. */ /* Set up strategy for branch-and-cut. Note that the integer code supplied to setupPreProcessing is *not* compatible with the IPPAction enum. But at least it's documented. See desiredPreProcess_ in CbcStrategyDefault. `1' is accidentally equivalent to IPPOn. */ if (ippAction == CbcGenCtlBlk::IPPStrategy) { CbcStrategyDefault strategy(true, 5, 5) ; strategy.setupPreProcessing(1) ; babModel.setStrategy(strategy) ; } /* Yes! At long last, we're ready for the big call. Do branch and cut. In general, the solver used to return the solution will not be the solver we passed in, so reset babSolver here. */ int statistics = (ctlBlk->printOpt_ > 0) ? ctlBlk->printOpt_ : 0 ; # if CBC_TRACK_SOLVERS > 0 std::cout << "doBaCParam: solver at call to branchAndBound is " << std::hex << babModel.solver() << std::dec << ", log level " << babModel.solver()->messageHandler()->logLevel() << "." << std::endl ; # endif babModel.branchAndBound(statistics) ; babSolver = babModel.solver() ; # if CBC_TRACK_SOLVERS > 0 std::cout << "doBaCParam: solver at return from branchAndBound is " << std::hex << babModel.solver() << std::dec << ", log level " << babModel.solver()->messageHandler()->logLevel() << "." << std::endl ; # endif /* Write out solution to preprocessed model. */ if (ctlBlk->debugCreate_ == "createAfterPre" && babModel.bestSolution()) { CbcGenParamUtils::saveSolution(babSolver, "debug.file") ; } /* Print some information about branch-and-cut. */ # if COIN_CBC_VERBOSITY > 0 std::cout << "Cuts at root node changed objective from " << babModel.getContinuousObjective() << " to " << babModel.rootObjectiveAfterCuts() << std::endl ; for (int iGen = 0 ; iGen < babModel.numberCutGenerators() ; iGen++) { CbcCutGenerator *generator = babModel.cutGenerator(iGen) ; 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::cout << std::endl ; } # endif time2 = CoinCpuTime(); ctlBlk->totalTime_ += time2 - time1; /* If we performed integer preprocessing, time to back it out. */ if (ippAction != CbcGenCtlBlk::IPPOff) { # if CBC_TRACK_SOLVERS > 0 std::cout << "doBaCParam: solver passed to IPP postprocess is " << std::hex << babSolver << std::dec << "." << std::endl ; # endif ippObj.postProcess(*babSolver); babModel.assignSolver(preIppSolver) ; babSolver = babModel.solver() ; # if CBC_TRACK_SOLVERS > 0 std::cout << "doBaCParam: solver in babModel after IPP postprocess is " << std::hex << babSolver << std::dec << "." << std::endl ; # endif } /* Write out postprocessed solution to debug file, if requested. */ if (ctlBlk->debugCreate_ == "create" && babModel.bestSolution()) { CbcGenParamUtils::saveSolution(babSolver, "debug.file") ; } /* If we have a good solution, detach the solver with the answer. Fill in the rest of the status information for the benefit of the wider world. */ bool keepAnswerSolver = false ; OsiSolverInterface *answerSolver = 0 ; if (babModel.bestSolution()) { babModel.setModelOwnsSolver(false) ; keepAnswerSolver = true ; answerSolver = babSolver ; } ctlBlk->setBaBStatus(&babModel, CbcGenCtlBlk::BACwBAC, keepAnswerSolver, answerSolver) ; /* And one last bit of information & statistics. */ ctlBlk->printBaBStatus() ; std::cout << " " ; if (keepAnswerSolver) { std::cout << "objective " << babModel.getObjValue() << "; " ; } std::cout << babModel.getNodeCount() << " nodes and " << babModel.getIterationCount() << " iterations - took " << time2 - time1 << " seconds" << std::endl ; return (0) ; }