double CbcGeneralBranchingObject::branch() { double cutoff = model_->getCutoff(); //printf("GenB %x whichNode %d numberLeft %d which %d\n", // this,whichNode_,numberBranchesLeft(),branchIndex()); if (whichNode_ < 0) { assert (node_); bool applied = false; while (numberBranchesLeft()) { int which = branchIndex(); decrementNumberBranchesLeft(); CbcSubProblem * thisProb = subProblems_ + which; if (thisProb->objectiveValue_ < cutoff) { //printf("branch %x (sub %x) which now %d\n",this, // subProblems_,which); OsiSolverInterface * solver = model_->solver(); thisProb->apply(solver); OsiClpSolverInterface * clpSolver = dynamic_cast<OsiClpSolverInterface *> (solver); assert (clpSolver); // Move status to basis clpSolver->setWarmStart(NULL); //ClpSimplex * simplex = clpSolver->getModelPtr(); node_->setObjectiveValue(thisProb->objectiveValue_); node_->setSumInfeasibilities(thisProb->sumInfeasibilities_); node_->setNumberUnsatisfied(thisProb->numberInfeasibilities_); applied = true; doingDoneBranch = true; break; } else if (numberBranchesLeft()) { node_->nodeInfo()->branchedOn() ; } } if (!applied) { // no good one node_->setObjectiveValue(cutoff + 1.0e20); node_->setSumInfeasibilities(1.0); node_->setNumberUnsatisfied(1); assert (whichNode_ < 0); } } else { decrementNumberBranchesLeft(); CbcSubProblem * thisProb = subProblems_ + whichNode_; assert (thisProb->objectiveValue_ < cutoff); OsiSolverInterface * solver = model_->solver(); thisProb->apply(solver); //OsiClpSolverInterface * clpSolver //= dynamic_cast<OsiClpSolverInterface *> (solver); //assert (clpSolver); // Move status to basis //clpSolver->setWarmStart(NULL); } return 0.0; }
void LinearCutsGenerator::generateCuts(const OsiSolverInterface &solver, OsiCuts &cs, const CglTreeInfo info) const { //const OsiTMINLPInterface * tmp = dynamic_cast<const OsiTMINLPInterface *>(&solver); OsiTMINLPInterface * nlp = dynamic_cast<OsiTMINLPInterface *>(solver.clone());//const_cast<OsiTMINLPInterface *>(tmp); assert(nlp); OuterApprox oa; //si.writeMps("toto"); int numberRows = nlp->getNumRows(); for(int i = 0 ; i < 5 ; i++){ nlp->resolve(); OsiClpSolverInterface si; oa(*nlp, &si, solver.getColSolution(), true); si.resolve(); OsiCuts cuts; for(std::list<Coin::SmartPtr<CuttingMethod> >::const_iterator i = methods_.begin() ; i != methods_.end() ; i++){ (*i)->cgl->generateCuts(si, cuts, info); } std::vector<OsiRowCut *> mycuts(cuts.sizeRowCuts()); for(int i = 0 ; i < cuts.sizeRowCuts() ; i++){ mycuts[i] = cuts.rowCutPtr(i); cs.insert(*mycuts[i]); } nlp->applyRowCuts(mycuts.size(), const_cast<const OsiRowCut **> (&mycuts[0])); } // Take off slack cuts std::vector<int> kept; int numberRowsNow = nlp->getNumRows(); int * del = new int [numberRowsNow-numberRows]; nlp->resolve(); const double * activity = nlp->getRowActivity(); const double * lb = nlp->getRowLower(); const double * ub = nlp->getRowUpper(); CoinRelFltEq eq(1e-06); //int nDelete=0; for (int i=numberRowsNow -1;i>=numberRows;i--) { if ( !(eq(activity[i], lb[i]) || eq(activity[i], ub[i])) ) cs.eraseRowCut(i - numberRows); } delete [] del; delete nlp; }
// nothing to inherit from GC really ColoredGraph solve(const Graph& gr) override { CoinModel coinModel; for (auto i = 0; i < gr.nodeCount(); ++i) { coinModel.addCol(0, nullptr, nullptr, 0, gr.nodeCount()-1, 1, nullptr, true); } OsiClpSolverInterface solver; solver.loadFromCoinModel(coinModel); CbcModel model(solver); model.setLogLevel(0); model.passInEventHandler(make_unique<GC_LP_EventHandler>(recoveryPath).get()); if (use_heuristic) { GC_LP_Heuristic heuristic; model.addHeuristic(&heuristic); } AddRules(model, gr); if (use_parallel) { model.setNumberThreads(std::thread::hardware_concurrency()); } if (max_seconds != 0) model.setMaximumSeconds(max_seconds); model.initialSolve(); model.branchAndBound(); if (model.maximumSecondsReached()) Println(cout, "max seconds reached"); if (model.isSecondsLimitReached()) Println(cout, "seconds limit reached"); seconds_passed_ = model.getCurrentSeconds(); iterations_passed_ = model.getIterationCount(); const double *solution = model.bestSolution(); if (solution == nullptr) { vector<Color> colors(gr.nodeCount()); iota(colors.begin(), colors.end(), 0); return {gr, colors}; } return ColoredGraph(gr, {solution, solution+gr.nodeCount()}); }
int main(int argc, char *argv[]) { try{ // Set up lp solver OsiClpSolverInterface lpSolver; lpSolver.getModelPtr()->setDualBound(1.0e10); lpSolver.messageHandler()->setLogLevel(0); // Create BLIS model BlisModel model; model.setSolver(&lpSolver); #ifdef COIN_HAS_MPI AlpsKnowledgeBrokerMPI broker(argc, argv, model); #else AlpsKnowledgeBrokerSerial broker(argc, argv, model); #endif // Search for best solution broker.search(&model); // Report the best solution found and its ojective value broker.printBestSolution(); } catch(CoinError& er) { std::cerr << "\nBLIS ERROR: \"" << er.message() << "\""<< std::endl << " from function \"" << er.methodName() << "\""<< std::endl << " from class \"" << er.className() << "\"" << std::endl; } catch(...) { std::cerr << "Something went wrong!" << std::endl; } return 0; }
CbcBranchingObject * CbcGeneralDepth::createCbcBranch(OsiSolverInterface * solver, const OsiBranchingInformation * info, int /*way*/) { int numberDo = numberNodes_; if (whichSolution_ >= 0 && (model_->moreSpecialOptions()&33554432)==0) numberDo--; assert (numberDo > 0); // create object CbcGeneralBranchingObject * branch = new CbcGeneralBranchingObject(model_); // skip solution branch->numberSubProblems_ = numberDo; // If parentBranch_ back in then will have to be 2* branch->numberSubLeft_ = numberDo; branch->setNumberBranches(numberDo); CbcSubProblem * sub = new CbcSubProblem[numberDo]; int iProb = 0; branch->subProblems_ = sub; branch->numberRows_ = model_->solver()->getNumRows(); int iNode; //OsiSolverInterface * solver = model_->solver(); OsiClpSolverInterface * clpSolver = dynamic_cast<OsiClpSolverInterface *> (solver); assert (clpSolver); ClpSimplex * simplex = clpSolver->getModelPtr(); int numberColumns = simplex->numberColumns(); if ((model_->moreSpecialOptions()&33554432)==0) { double * lowerBefore = CoinCopyOfArray(simplex->getColLower(), numberColumns); double * upperBefore = CoinCopyOfArray(simplex->getColUpper(), numberColumns); ClpNodeStuff * info = nodeInfo_; double * weight = new double[numberNodes_]; int * whichNode = new int [numberNodes_]; // Sort for (iNode = 0; iNode < numberNodes_; iNode++) { if (iNode != whichSolution_) { double objectiveValue = info->nodeInfo_[iNode]->objectiveValue(); double sumInfeasibilities = info->nodeInfo_[iNode]->sumInfeasibilities(); int numberInfeasibilities = info->nodeInfo_[iNode]->numberInfeasibilities(); double thisWeight = 0.0; #if 1 // just closest thisWeight = 1.0e9 * numberInfeasibilities; thisWeight += sumInfeasibilities; thisWeight += 1.0e-7 * objectiveValue; // Try estimate thisWeight = info->nodeInfo_[iNode]->estimatedSolution(); #else thisWeight = 1.0e-3 * numberInfeasibilities; thisWeight += 1.0e-5 * sumInfeasibilities; thisWeight += objectiveValue; #endif whichNode[iProb] = iNode; weight[iProb++] = thisWeight; } } assert (iProb == numberDo); CoinSort_2(weight, weight + numberDo, whichNode); for (iProb = 0; iProb < numberDo; iProb++) { iNode = whichNode[iProb]; ClpNode * node = info->nodeInfo_[iNode]; // move bounds node->applyNode(simplex, 3); // create subproblem sub[iProb] = CbcSubProblem(clpSolver, lowerBefore, upperBefore, node->statusArray(), node->depth()); sub[iProb].objectiveValue_ = node->objectiveValue(); sub[iProb].sumInfeasibilities_ = node->sumInfeasibilities(); sub[iProb].numberInfeasibilities_ = node->numberInfeasibilities(); #ifdef CHECK_PATH if (simplex->numberColumns() == numberColumns_Z) { bool onOptimal = true; const double * columnLower = simplex->columnLower(); const double * columnUpper = simplex->columnUpper(); for (int i = 0; i < numberColumns_Z; i++) { if (iNode == gotGoodNode_Z) printf("good %d %d %g %g\n", iNode, i, columnLower[i], columnUpper[i]); if (columnUpper[i] < debuggerSolution_Z[i] || columnLower[i] > debuggerSolution_Z[i] && simplex->isInteger(i)) { onOptimal = false; break; } } if (onOptimal) { printf("adding to node %x as %d - objs\n", this, iProb); for (int j = 0; j <= iProb; j++) printf("%d %g\n", j, sub[j].objectiveValue_); } } #endif } delete [] weight; delete [] whichNode; const double * lower = solver->getColLower(); const double * upper = solver->getColUpper(); // restore bounds for ( int j = 0; j < numberColumns; j++) { if (lowerBefore[j] != lower[j]) solver->setColLower(j, lowerBefore[j]); if (upperBefore[j] != upper[j]) solver->setColUpper(j, upperBefore[j]); } delete [] upperBefore; delete [] lowerBefore; } else { // from diving CbcSubProblem ** nodes = reinterpret_cast<CbcSubProblem **> (model_->temporaryPointer()); assert (nodes); int adjustDepth=info->depth_; assert (numberDo); numberNodes_=0; for (iProb = 0; iProb < numberDo; iProb++) { if ((nodes[iProb]->problemStatus_&2)==0) { // create subproblem (and swap way and/or make inactive) sub[numberNodes_].takeOver(*nodes[iProb],true); // but adjust depth sub[numberNodes_].depth_+=adjustDepth; numberNodes_++; } delete nodes[iProb]; } branch->numberSubProblems_ = numberNodes_; branch->numberSubLeft_ = numberNodes_; branch->setNumberBranches(numberNodes_); if (!numberNodes_) { // infeasible delete branch; branch=NULL; } delete [] nodes; } return branch; }
// Infeasibility - large is 0.5 double CbcGeneralDepth::infeasibility(const OsiBranchingInformation * /*info*/, int &/*preferredWay*/) const { whichSolution_ = -1; // should use genuine OsiBranchingInformation usefulInfo = model_->usefulInformation(); // for now assume only called when correct //if (usefulInfo.depth_>=4&&!model_->parentModel() // &&(usefulInfo.depth_%2)==0) { if (true) { OsiSolverInterface * solver = model_->solver(); OsiClpSolverInterface * clpSolver = dynamic_cast<OsiClpSolverInterface *> (solver); if (clpSolver) { if ((model_->moreSpecialOptions()&33554432)==0) { ClpNodeStuff * info = nodeInfo_; info->integerTolerance_ = model_->getIntegerTolerance(); info->integerIncrement_ = model_->getCutoffIncrement(); info->numberBeforeTrust_ = model_->numberBeforeTrust(); info->stateOfSearch_ = model_->stateOfSearch(); // Compute "small" change in branch int nBranches = model_->getIntParam(CbcModel::CbcNumberBranches); if (nBranches) { double average = model_->getDblParam(CbcModel::CbcSumChange) / static_cast<double>(nBranches); info->smallChange_ = CoinMax(average * 1.0e-5, model_->getDblParam(CbcModel::CbcSmallestChange)); info->smallChange_ = CoinMax(info->smallChange_, 1.0e-8); } else { info->smallChange_ = 1.0e-8; } int numberIntegers = model_->numberIntegers(); double * down = new double[numberIntegers]; double * up = new double[numberIntegers]; int * priority = new int[numberIntegers]; int * numberDown = new int[numberIntegers]; int * numberUp = new int[numberIntegers]; int * numberDownInfeasible = new int[numberIntegers]; int * numberUpInfeasible = new int[numberIntegers]; model_->fillPseudoCosts(down, up, priority, numberDown, numberUp, numberDownInfeasible, numberUpInfeasible); info->fillPseudoCosts(down, up, priority, numberDown, numberUp, numberDownInfeasible, numberUpInfeasible, numberIntegers); info->presolveType_ = 1; delete [] down; delete [] up; delete [] numberDown; delete [] numberUp; delete [] numberDownInfeasible; delete [] numberUpInfeasible; bool takeHint; OsiHintStrength strength; solver->getHintParam(OsiDoReducePrint, takeHint, strength); ClpSimplex * simplex = clpSolver->getModelPtr(); int saveLevel = simplex->logLevel(); if (strength != OsiHintIgnore && takeHint && saveLevel == 1) simplex->setLogLevel(0); clpSolver->setBasis(); whichSolution_ = simplex->fathomMany(info); //printf("FAT %d nodes, %d iterations\n", //info->numberNodesExplored_,info->numberIterations_); //printf("CbcBranch %d rows, %d columns\n",clpSolver->getNumRows(), // clpSolver->getNumCols()); model_->incrementExtra(info->numberNodesExplored_, info->numberIterations_); // update pseudo costs double smallest = 1.0e50; double largest = -1.0; OsiObject ** objects = model_->objects(); #ifndef NDEBUG const int * integerVariable = model_->integerVariable(); #endif for (int i = 0; i < numberIntegers; i++) { #ifndef NDEBUG CbcSimpleIntegerDynamicPseudoCost * obj = dynamic_cast <CbcSimpleIntegerDynamicPseudoCost *>(objects[i]) ; assert (obj && obj->columnNumber() == integerVariable[i]); #else CbcSimpleIntegerDynamicPseudoCost * obj = static_cast <CbcSimpleIntegerDynamicPseudoCost *>(objects[i]) ; #endif if (info->numberUp_[i] > 0) { if (info->downPseudo_[i] > largest) largest = info->downPseudo_[i]; if (info->downPseudo_[i] < smallest) smallest = info->downPseudo_[i]; if (info->upPseudo_[i] > largest) largest = info->upPseudo_[i]; if (info->upPseudo_[i] < smallest) smallest = info->upPseudo_[i]; obj->updateAfterMini(info->numberDown_[i], info->numberDownInfeasible_[i], info->downPseudo_[i], info->numberUp_[i], info->numberUpInfeasible_[i], info->upPseudo_[i]); } } //printf("range of costs %g to %g\n",smallest,largest); simplex->setLogLevel(saveLevel); numberNodes_ = info->nNodes_; } else { // Try diving // See if any diving heuristics set to do dive+save CbcHeuristicDive * dive=NULL; for (int i = 0; i < model_->numberHeuristics(); i++) { CbcHeuristicDive * possible = dynamic_cast<CbcHeuristicDive *>(model_->heuristic(i)); if (possible&&possible->maxSimplexIterations()==COIN_INT_MAX) { // if more than one then rotate later? //if (possible->canHeuristicRun()) { dive=possible; break; } } assert (dive); // otherwise moreSpecial should have been turned off CbcSubProblem ** nodes=NULL; int branchState=dive->fathom(model_,numberNodes_,nodes); if (branchState) { printf("new solution\n"); whichSolution_=numberNodes_-1; } else { whichSolution_=-1; } #if 0 if (0) { for (int iNode=0;iNode<numberNodes;iNode++) { //tree_->push(nodes[iNode]) ; } assert (node->nodeInfo()); if (node->nodeInfo()->numberBranchesLeft()) { tree_->push(node) ; } else { node->setActive(false); } } #endif //delete [] nodes; model_->setTemporaryPointer(reinterpret_cast<void *>(nodes)); // end try diving } int numberDo = numberNodes_; if (numberDo > 0 || whichSolution_ >= 0) { return 0.5; } else { // no solution return COIN_DBL_MAX; // say infeasible } } else { return -1.0; } } else { return -1.0; } }
// Generate cuts void CglFakeClique::generateCuts(const OsiSolverInterface& si, OsiCuts & cs, const CglTreeInfo info) { if (fakeSolver_) { assert (si.getNumCols()==fakeSolver_->getNumCols()); fakeSolver_->setColLower(si.getColLower()); const double * solution = si.getColSolution(); fakeSolver_->setColSolution(solution); fakeSolver_->setColUpper(si.getColUpper()); // get and set branch and bound cutoff double cutoff; si.getDblParam(OsiDualObjectiveLimit,cutoff); fakeSolver_->setDblParam(OsiDualObjectiveLimit,COIN_DBL_MAX); #ifdef COIN_HAS_CLP OsiClpSolverInterface * clpSolver = dynamic_cast<OsiClpSolverInterface *> (fakeSolver_); if (clpSolver) { // fix up fake solver const ClpSimplex * siSimplex = clpSolver->getModelPtr(); // need to set djs memcpy(siSimplex->primalColumnSolution(), si.getReducedCost(),si.getNumCols()*sizeof(double)); fakeSolver_->setDblParam(OsiDualObjectiveLimit,cutoff); } #endif const CoinPackedMatrix * matrixByRow = si.getMatrixByRow(); const double * elementByRow = matrixByRow->getElements(); const int * column = matrixByRow->getIndices(); const CoinBigIndex * rowStart = matrixByRow->getVectorStarts(); const int * rowLength = matrixByRow->getVectorLengths(); const double * rowUpper = si.getRowUpper(); const double * rowLower = si.getRowLower(); // Scan all rows looking for possibles int numberRows = si.getNumRows(); double tolerance = 1.0e-3; for (int iRow=0;iRow<numberRows;iRow++) { CoinBigIndex start = rowStart[iRow]; CoinBigIndex end = start + rowLength[iRow]; double upRhs = rowUpper[iRow]; double loRhs = rowLower[iRow]; double sum = 0.0; for (CoinBigIndex j=start;j<end;j++) { int iColumn=column[j]; double value = elementByRow[j]; sum += solution[iColumn]*value; } if (sum<loRhs-tolerance||sum>upRhs+tolerance) { // add as cut OsiRowCut rc; rc.setLb(loRhs); rc.setUb(upRhs); rc.setRow(end-start,column+start,elementByRow+start,false); CoinAbsFltEq equal(1.0e-12); cs.insertIfNotDuplicate(rc,equal); } } CglClique::generateCuts(*fakeSolver_,cs,info); if (probing_) { probing_->generateCuts(*fakeSolver_,cs,info); } } else { // just use real solver CglClique::generateCuts(si,cs,info); } }
void ModelScenario(const char * const name ) { OsiClpSolverInterface *osiClp1 = new OsiClpSolverInterface(); double INF=osiClp1->getInfinity(); // example of direct interfaces for scenario generation /* Model dimensions */ int nels=44; // ncol=27, nrow=9 /* Sparse matrix data...organized by row */ int mrow[]={ 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8 }; int mcol[]={ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11, 12, 13, 14, 15, 16, 0, 12, 17, 18, 1, 5, 9, 13, 19, 20, 2, 6, 14, 21, 22, 3, 7, 10, 15, 23, 24, 4, 8, 11, 16, 25, 26 }; double dels[] = { 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, 1.0, 16.0, 9.0, -1.0, 1.0, 15.0, 10.0, 5.0, 11.0, -1.0, 1.0, 28.0, 14.0, 22.0, -1.0, 1.0, 23.0, 15.0, 7.0, 17.0, -1.0, 1.0, 81.0, 57.0, 29.0, 55.0, -1.0, 1.0 }; /* Objective */ double dobj[]={ 18.0, 21.0, 18.0, 16.0, 10.0, 15.0, 16.0, 14.0, 9.0, 10.0, 9.0, 6.0, 17.0, 16.0, 17.0, 15.0, 10.0, 0.0, 13.0, 0.0, 13.0, 0.0, 7.0, 0.0, 7.0, 0.0, 1.0 }; /* Column bounds */ double dclo[]={ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; double dcup[]={ INF, INF, INF, INF, INF, INF, INF, INF, INF, INF, INF, INF, INF, INF, INF, INF, INF, INF, INF, INF, INF, INF, INF, INF, INF, INF, INF }; /* Row bounds */ double drlo[]={ -INF, -INF, -INF, -INF, 0.0, 4.0, 0.0, 8.0, 10.0 }; double drup[]={ 10.0, 19.0, 25.0, 15.0, 0.0, 7.0, 0.0, 8.0, 90.0 }; /* Stages */ int nstg=2; int n_first_stg_rows=4; int rstg[]={ 0,0,0,0,1,1,1,1,1 }; int cstg[]={ 0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,1, 1,1,1,1,1,1,1,1,1 }; /* Stochastic data */ int nindp=5; int nsamp[]={ 5, 2, 5, 5, 3 }; double demand[]={ 200, 220, 250, 270, 300, 50, 150, 140, 160, 180, 200, 220, 10, 50, 80, 100, 340, 580, 600, 620 }; double dprobs[]={ 0.2, 0.05, 0.35, 0.2, 0.2, 0.3, 0.7, 0.1, 0.2, 0.4, 0.2, 0.1, 0.2, 0.2, 0.3, 0.2, 0.1, 0.1, 0.8, 0.1 }; /* local variables */ int ns=1,ii,iii,jj,*indx,*incr; double dp=1.0; for (ii=0;ii<nindp;ii++) ns *= nsamp[ii]; /* Compute number of scenarios */ // initialize SmiModel SmiScnModel *smiModel = new SmiScnModel(); smiModel->setOsiSolverHandle(*osiClp1); // set core model using Osi interface OsiClpSolverInterface ocsi; ocsi.loadProblem(CoinPackedMatrix( 1,mrow,mcol,dels,nels),dclo,dcup,dobj,drlo,drup); SmiCoreData *osiCore = new SmiCoreData(&ocsi,nstg,cstg,rstg); cout << "ModelScenario: Created CoreData" << endl; // Coin structures for scenario updates to right hand sides CoinPackedVector cpv_rlo; CoinPackedVector cpv_rup; // initialize right hand side data for first scenario indx = (int *) malloc( (1+nindp)*sizeof(int) ); memset( indx,0,(1+nindp)*sizeof(int)); for (jj=0;jj<nindp;jj++) { indx[jj+1] += indx[jj] + nsamp[jj]; dp *= dprobs[ indx[jj] ]; drlo[n_first_stg_rows + jj] = demand[ indx[jj] ]; drup[n_first_stg_rows + jj] = demand[ indx[jj] ]; cpv_rlo.insert(n_first_stg_rows + jj,demand[ indx[jj] ]); cpv_rup.insert(n_first_stg_rows + jj,demand[ indx[jj] ]); } cout << "ModelScenario: Adding " << ns << " scenarios" << endl; // first scenario int anc = 0; int branch = 1; int is = smiModel->generateScenario(osiCore,NULL,NULL,NULL,NULL, &cpv_rlo,&cpv_rup,branch,anc,dp); /***** ...main loop to generate scenarios from discrete random variables For each scenario index ii: If the sample size nsamp[jj] divides the scenario index ii, reverse the increment direction incr[jj] and increase the random variable index jj by 1. Increment the jj'th random variable by incr[jj] and generate new sample data. ***** */ /* sample space increment initialized to 1 */ incr = (int *) malloc( nindp*sizeof(int) ); for (jj=0;jj<nindp;jj++) incr[jj] = 1; for (int iss=1;iss<ns;iss++) { iii=iss; jj=0; while ( !(iii%nsamp[jj]) ) { iii /= nsamp[jj]; incr[jj] = -incr[jj]; jj++; } dp /= dprobs[ indx[jj] ]; indx[jj] += incr[jj]; dp *= dprobs[ indx[jj] ]; // set data drlo[n_first_stg_rows + jj] = demand[ indx[jj] ]; drup[n_first_stg_rows + jj] = demand[ indx[jj] ]; cpv_rlo.setElement(cpv_rlo.findIndex(n_first_stg_rows + jj),demand[ indx[jj] ]); cpv_rup.setElement(cpv_rup.findIndex(n_first_stg_rows + jj),demand[ indx[jj] ]); // genScenario is = smiModel->generateScenario(osiCore,NULL,NULL,NULL,NULL, &cpv_rlo,&cpv_rup,branch,anc,dp); } assert(ns==smiModel->getNumScenarios()); cout << "ModelScenario: Finished adding scenarios" << endl; // load problem data into OsiSolver smiModel->loadOsiSolverData(); // get Osi pointer OsiSolverInterface *smiOsi = smiModel->getOsiSolverInterface(); // set some parameters smiOsi->setHintParam(OsiDoPresolveInInitial,true); smiOsi->setHintParam(OsiDoScale,true); smiOsi->setHintParam(OsiDoCrash,true); // solve using Osi Solver smiOsi->initialSolve(); // test optimal value assert(fabs(smiOsi->getObjValue()-1566.042)<0.01); // test solutions const double *dsoln = smiOsi->getColSolution(); double objSum = 0.0; /* The canonical way to traverse the tree: For each scenario, get the leaf node. Then get the parent. Repeat until parent is NULL. (Only the root node has a NULL parent.) */ for(is=0; is<ns; ++is) { /* this loop calculates the scenario objective value */ double scenSum = 0.0; // start with leaf node SmiScnNode *node = smiModel->getLeafNode(is); // leaf node probability is the scenario probability double scenprob = node->getModelProb(); while (node != NULL) { // getColStart returns the starting index of node in OSI model for(int j=node->getColStart(); j<node->getColStart()+node->getNumCols(); ++j) { // getCoreColIndex returns the corresponding Core index // in the original (user's) ordering scenSum += dobj[node->getCoreColIndex(j)]*dsoln[j]; } // get parent of node node = node->getParent(); } objSum += scenSum*scenprob; } assert(fabs(smiOsi->getObjValue()-objSum) < 0.01); // print results printf("Solved stochastic program %s\n", name); printf("Number of rows: %d\n",smiOsi->getNumRows()); printf("Number of cols: %d\n",smiOsi->getNumCols()); printf("Optimal value: %g\n",smiOsi->getObjValue()); }
int CbcHeuristicDive::reducedCostFix (OsiSolverInterface* solver) { //return 0; // temp #ifndef JJF_ONE if (!model_->solverCharacteristics()->reducedCostsAccurate()) return 0; //NLP #endif double cutoff = model_->getCutoff() ; if (cutoff > 1.0e20) return 0; #ifdef DIVE_DEBUG std::cout << "cutoff = " << cutoff << std::endl; #endif double direction = solver->getObjSense() ; double gap = cutoff - solver->getObjValue() * direction ; gap *= 0.5; // Fix more double tolerance; solver->getDblParam(OsiDualTolerance, tolerance) ; if (gap <= 0.0) gap = tolerance; //return 0; gap += 100.0 * tolerance; double integerTolerance = model_->getDblParam(CbcModel::CbcIntegerTolerance); const double *lower = solver->getColLower() ; const double *upper = solver->getColUpper() ; const double *solution = solver->getColSolution() ; const double *reducedCost = solver->getReducedCost() ; int numberIntegers = model_->numberIntegers(); const int * integerVariable = model_->integerVariable(); int numberFixed = 0 ; # ifdef COIN_HAS_CLP OsiClpSolverInterface * clpSolver = dynamic_cast<OsiClpSolverInterface *> (solver); ClpSimplex * clpSimplex = NULL; if (clpSolver) clpSimplex = clpSolver->getModelPtr(); # endif for (int i = 0 ; i < numberIntegers ; i++) { int iColumn = integerVariable[i] ; double djValue = direction * reducedCost[iColumn] ; if (upper[iColumn] - lower[iColumn] > integerTolerance) { if (solution[iColumn] < lower[iColumn] + integerTolerance && djValue > gap) { #ifdef COIN_HAS_CLP // may just have been fixed before if (clpSimplex) { if (clpSimplex->getColumnStatus(iColumn) == ClpSimplex::basic) { #ifdef COIN_DEVELOP printf("DJfix %d has status of %d, dj of %g gap %g, bounds %g %g\n", iColumn, clpSimplex->getColumnStatus(iColumn), djValue, gap, lower[iColumn], upper[iColumn]); #endif } else { assert(clpSimplex->getColumnStatus(iColumn) == ClpSimplex::atLowerBound || clpSimplex->getColumnStatus(iColumn) == ClpSimplex::isFixed); } } #endif solver->setColUpper(iColumn, lower[iColumn]) ; numberFixed++ ; } else if (solution[iColumn] > upper[iColumn] - integerTolerance && -djValue > gap) { #ifdef COIN_HAS_CLP // may just have been fixed before if (clpSimplex) { if (clpSimplex->getColumnStatus(iColumn) == ClpSimplex::basic) { #ifdef COIN_DEVELOP printf("DJfix %d has status of %d, dj of %g gap %g, bounds %g %g\n", iColumn, clpSimplex->getColumnStatus(iColumn), djValue, gap, lower[iColumn], upper[iColumn]); #endif } else { assert(clpSimplex->getColumnStatus(iColumn) == ClpSimplex::atUpperBound || clpSimplex->getColumnStatus(iColumn) == ClpSimplex::isFixed); } } #endif solver->setColLower(iColumn, upper[iColumn]) ; numberFixed++ ; } } } return numberFixed; }
int main (int argc, const char *argv[]) { // Define your favorite OsiSolver OsiClpSolverInterface solver1; // Read in model using argv[1] // and assert that it is a clean model std::string dirsep(1,CoinFindDirSeparator()); std::string mpsFileName; # if defined(SAMPLEDIR) mpsFileName = SAMPLEDIR ; mpsFileName += dirsep+"p0033.mps"; # else if (argc < 2) { fprintf(stderr, "Do not know where to find sample MPS files.\n"); exit(1); } # endif if (argc>=2) mpsFileName = argv[1]; int numMpsReadErrors = solver1.readMps(mpsFileName.c_str(),""); if( numMpsReadErrors != 0 ) { printf("%d errors reading MPS file\n", numMpsReadErrors); return numMpsReadErrors; } double time1 = CoinCpuTime(); /* Options are: preprocess to do preprocessing time in minutes if 2 parameters and numeric taken as time */ bool preProcess=false; double minutes=-1.0; int nGoodParam=0; for (int iParam=2; iParam<argc;iParam++) { if (!strcmp(argv[iParam],"preprocess")) { preProcess=true; nGoodParam++; } else if (!strcmp(argv[iParam],"time")) { if (iParam+1<argc&&isdigit(argv[iParam+1][0])) { minutes=atof(argv[iParam+1]); if (minutes>=0.0) { nGoodParam+=2; iParam++; // skip time } } } } if (nGoodParam==0&&argc==3&&isdigit(argv[2][0])) { // If time is given then stop after that number of minutes minutes = atof(argv[2]); if (minutes>=0.0) nGoodParam=1; } if (nGoodParam!=argc-2&&argc>=2) { printf("Usage <file> [preprocess] [time <minutes>] or <file> <minutes>\n"); exit(1); } solver1.initialSolve(); // Reduce printout solver1.setHintParam(OsiDoReducePrint,true,OsiHintTry); // See if we want preprocessing OsiSolverInterface * solver2=&solver1; #if PREPROCESS==1 CglPreProcess process; if (preProcess) { /* Do not try and produce equality cliques and do up to 5 passes */ solver2 = process.preProcess(solver1,false,5); if (!solver2) { printf("Pre-processing says infeasible\n"); exit(2); } solver2->resolve(); } #endif CbcModel model(*solver2); model.solver()->setHintParam(OsiDoReducePrint,true,OsiHintTry); // Set up some cut generators and defaults // Probing first as gets tight bounds on continuous CglProbing generator1; generator1.setUsingObjective(true); generator1.setMaxPass(1); generator1.setMaxPassRoot(5); // Number of unsatisfied variables to look at generator1.setMaxProbe(10); generator1.setMaxProbeRoot(1000); // How far to follow the consequences generator1.setMaxLook(50); generator1.setMaxLookRoot(500); // Only look at rows with fewer than this number of elements generator1.setMaxElements(200); generator1.setRowCuts(3); CglGomory generator2; // try larger limit generator2.setLimit(300); CglKnapsackCover generator3; CglRedSplit generator4; // try larger limit generator4.setLimit(200); CglClique generator5; generator5.setStarCliqueReport(false); generator5.setRowCliqueReport(false); CglMixedIntegerRounding2 mixedGen; CglFlowCover flowGen; // Add in generators // Experiment with -1 and -99 etc model.addCutGenerator(&generator1,-1,"Probing"); model.addCutGenerator(&generator2,-1,"Gomory"); model.addCutGenerator(&generator3,-1,"Knapsack"); // model.addCutGenerator(&generator4,-1,"RedSplit"); model.addCutGenerator(&generator5,-1,"Clique"); model.addCutGenerator(&flowGen,-1,"FlowCover"); model.addCutGenerator(&mixedGen,-1,"MixedIntegerRounding"); // Say we want timings int numberGenerators = model.numberCutGenerators(); int iGenerator; for (iGenerator=0;iGenerator<numberGenerators;iGenerator++) { CbcCutGenerator * generator = model.cutGenerator(iGenerator); generator->setTiming(true); } OsiClpSolverInterface * osiclp = dynamic_cast< OsiClpSolverInterface*> (model.solver()); // go faster stripes if (osiclp) { // Turn this off if you get problems // Used to be automatically set osiclp->setSpecialOptions(128); if(osiclp->getNumRows()<300&&osiclp->getNumCols()<500) { //osiclp->setupForRepeatedUse(2,0); osiclp->setupForRepeatedUse(0,0); } } // Uncommenting this should switch off all CBC messages // model.messagesPointer()->setDetailMessages(10,10000,NULL); // Allow rounding heuristic CbcRounding heuristic1(model); model.addHeuristic(&heuristic1); // And local search when new solution found CbcHeuristicLocal heuristic2(model); model.addHeuristic(&heuristic2); // Redundant definition of default branching (as Default == User) CbcBranchUserDecision branch; model.setBranchingMethod(&branch); // Definition of node choice CbcCompareUser compare; model.setNodeComparison(compare); // Do initial solve to continuous model.initialSolve(); // Could tune more double objValue = model.solver()->getObjSense()*model.solver()->getObjValue(); double minimumDropA=CoinMin(1.0,fabs(objValue)*1.0e-3+1.0e-4); double minimumDrop= fabs(objValue)*1.0e-4+1.0e-4; printf("min drop %g (A %g)\n",minimumDrop,minimumDropA); model.setMinimumDrop(minimumDrop); if (model.getNumCols()<500) model.setMaximumCutPassesAtRoot(-100); // always do 100 if possible else if (model.getNumCols()<5000) model.setMaximumCutPassesAtRoot(100); // use minimum drop else model.setMaximumCutPassesAtRoot(20); model.setMaximumCutPasses(10); //model.setMaximumCutPasses(2); // Switch off strong branching if wanted // model.setNumberStrong(0); // Do more strong branching if small if (model.getNumCols()<5000) model.setNumberStrong(10); model.setNumberStrong(20); //model.setNumberStrong(5); model.setNumberBeforeTrust(5); model.solver()->setIntParam(OsiMaxNumIterationHotStart,100); // If time is given then stop after that number of minutes if (minutes>=0.0) { std::cout<<"Stopping after "<<minutes<<" minutes"<<std::endl; model.setDblParam(CbcModel::CbcMaximumSeconds,60.0*minutes); } // Switch off most output if (model.getNumCols()<3000) { model.messageHandler()->setLogLevel(1); //model.solver()->messageHandler()->setLogLevel(0); } else { model.messageHandler()->setLogLevel(2); model.solver()->messageHandler()->setLogLevel(1); } //model.messageHandler()->setLogLevel(2); //model.solver()->messageHandler()->setLogLevel(2); //model.setPrintFrequency(50); //#define DEBUG_CUTS #ifdef DEBUG_CUTS // Set up debugger by name (only if no preprocesing) if (!preProcess) { std::string problemName ; model.solver()->getStrParam(OsiProbName,problemName) ; model.solver()->activateRowCutDebugger(problemName.c_str()) ; } #endif #if PREPROCESS==2 // Default strategy will leave cut generators as they exist already // so cutsOnlyAtRoot (1) ignored // numberStrong (2) is 5 (default) // numberBeforeTrust (3) is 5 (default is 0) // printLevel (4) defaults (0) CbcStrategyDefault strategy(true,5,5); // Set up pre-processing to find sos if wanted if (preProcess) strategy.setupPreProcessing(2); model.setStrategy(strategy); #endif // Do complete search model.branchAndBound(); std::cout<<mpsFileName<<" took "<<CoinCpuTime()-time1<<" seconds, " <<model.getNodeCount()<<" nodes with objective " <<model.getObjValue() <<(!model.status() ? " Finished" : " Not finished") <<std::endl; // Print more statistics std::cout<<"Cuts at root node changed objective from "<<model.getContinuousObjective() <<" to "<<model.rootObjectiveAfterCuts()<<std::endl; for (iGenerator=0;iGenerator<numberGenerators;iGenerator++) { CbcCutGenerator * generator = model.cutGenerator(iGenerator); std::cout<<generator->cutGeneratorName()<<" was tried " <<generator->numberTimesEntered()<<" times and created " <<generator->numberCutsInTotal()<<" cuts of which " <<generator->numberCutsActive()<<" were active after adding rounds of cuts"; if (generator->timing()) std::cout<<" ( "<<generator->timeInCutGenerator()<<" seconds)"<<std::endl; else std::cout<<std::endl; } // Print solution if finished - we can't get names from Osi! - so get from OsiClp if (model.getMinimizationObjValue()<1.0e50) { #if PREPROCESS==1 // post process OsiSolverInterface * solver; if (preProcess) { process.postProcess(*model.solver()); // Solution now back in solver1 solver = & solver1; } else { solver = model.solver(); } #else OsiSolverInterface * solver = model.solver(); #endif int numberColumns = solver->getNumCols(); const double * solution = solver->getColSolution(); // Get names from solver1 (as OsiSolverInterface may lose) std::vector<std::string> columnNames = *solver1.getModelPtr()->columnNames(); int iColumn; std::cout<<std::setiosflags(std::ios::fixed|std::ios::showpoint)<<std::setw(14); std::cout<<"--------------------------------------"<<std::endl; for (iColumn=0;iColumn<numberColumns;iColumn++) { double value=solution[iColumn]; if (fabs(value)>1.0e-7&&solver->isInteger(iColumn)) std::cout<<std::setw(6)<<iColumn<<" " <<columnNames[iColumn]<<" " <<value<<std::endl; } std::cout<<"--------------------------------------"<<std::endl; std::cout<<std::resetiosflags(std::ios::fixed|std::ios::showpoint|std::ios::scientific); } return 0; }
int main (int argc, const char *argv[]) { /* Define your favorite OsiSolver. CbcModel clones the solver so use solver1 up to the time you pass it to CbcModel then use a pointer to cloned solver (model.solver()) */ OsiClpSolverInterface solver1; /* From now on we can build model in a solver independent way. You can add rows one at a time but for large problems this is slow so this example uses CoinBuild or CoinModel */ OsiSolverInterface * solver = &solver1; // Data (is exmip1.mps in Mps/Sample // Objective double objValue[]={1.0,2.0,0.0,0.0,0.0,0.0,0.0,-1.0}; // Lower bounds for columns double columnLower[]={2.5,0.0,0.0,0.0,0.5,0.0,0.0,0.0}; // Upper bounds for columns double columnUpper[]={COIN_DBL_MAX,4.1,1.0,1.0,4.0, COIN_DBL_MAX,COIN_DBL_MAX,4.3}; // Lower bounds for row activities double rowLower[]={2.5,-COIN_DBL_MAX,-COIN_DBL_MAX,1.8,3.0}; // Upper bounds for row activities double rowUpper[]={COIN_DBL_MAX,2.1,4.0,5.0,15.0}; // Matrix stored packed int column[] = {0,1,3,4,7, 1,2, 2,5, 3,6, 4,7}; double element[] = {3.0,1.0,-2.0,-1.0,-1.0, 2.0,1.1, 1.0,1.0, 2.8,-1.2, 1.0,1.9}; int starts[]={0,5,7,9,11,13}; // Integer variables (note upper bound already 1.0) int whichInt[]={2,3}; int numberRows=(int) (sizeof(rowLower)/sizeof(double)); int numberColumns=(int) (sizeof(columnLower)/sizeof(double)); #define BUILD 2 #if BUILD==1 // Using CoinBuild // First do columns (objective and bounds) int i; // We are not adding elements for (i=0;i<numberColumns;i++) { solver->addCol(0,NULL,NULL,columnLower[i],columnUpper[i], objValue[i]); } // mark as integer for (i=0;i<(int) (sizeof(whichInt)/sizeof(int));i++) solver->setInteger(whichInt[i]); // Now build rows CoinBuild build; for (i=0;i<numberRows;i++) { int startRow = starts[i]; int numberInRow = starts[i+1]-starts[i]; build.addRow(numberInRow,column+startRow,element+startRow, rowLower[i],rowUpper[i]); } // add rows into solver solver->addRows(build); #else /* using CoinModel - more flexible but still beta. Can do exactly same way but can mix and match much more. Also all operations are on building object */ CoinModel build; // First do columns (objective and bounds) int i; for (i=0;i<numberColumns;i++) { build.setColumnBounds(i,columnLower[i],columnUpper[i]); build.setObjective(i,objValue[i]); } // mark as integer for (i=0;i<(int) (sizeof(whichInt)/sizeof(int));i++) build.setInteger(whichInt[i]); // Now build rows for (i=0;i<numberRows;i++) { int startRow = starts[i]; int numberInRow = starts[i+1]-starts[i]; build.addRow(numberInRow,column+startRow,element+startRow, rowLower[i],rowUpper[i]); } // add rows into solver solver->loadFromCoinModel(build); #endif // Pass to solver CbcModel model(*solver); model.solver()->setHintParam(OsiDoReducePrint,true,OsiHintTry); // Set up some cut generators and defaults // Probing first as gets tight bounds on continuous CglProbing generator1; generator1.setUsingObjective(true); generator1.setMaxPass(3); generator1.setMaxProbe(100); generator1.setMaxLook(50); generator1.setRowCuts(3); // generator1.snapshot(*model.solver()); //generator1.createCliques(*model.solver(),2,1000,true); //generator1.setMode(0); CglGomory generator2; // try larger limit generator2.setLimit(300); CglKnapsackCover generator3; CglOddHole generator4; generator4.setMinimumViolation(0.005); generator4.setMinimumViolationPer(0.00002); // try larger limit generator4.setMaximumEntries(200); CglClique generator5; generator5.setStarCliqueReport(false); generator5.setRowCliqueReport(false); CglMixedIntegerRounding mixedGen; CglFlowCover flowGen; // Add in generators model.addCutGenerator(&generator1,-1,"Probing"); model.addCutGenerator(&generator2,-1,"Gomory"); model.addCutGenerator(&generator3,-1,"Knapsack"); model.addCutGenerator(&generator4,-1,"OddHole"); model.addCutGenerator(&generator5,-1,"Clique"); model.addCutGenerator(&flowGen,-1,"FlowCover"); model.addCutGenerator(&mixedGen,-1,"MixedIntegerRounding"); OsiClpSolverInterface * osiclp = dynamic_cast< OsiClpSolverInterface*> (model.solver()); // go faster stripes if (osiclp->getNumRows()<300&&osiclp->getNumCols()<500) { osiclp->setupForRepeatedUse(2,0); printf("trying slightly less reliable but faster version (? Gomory cuts okay?)\n"); printf("may not be safe if doing cuts in tree which need accuracy (level 2 anyway)\n"); } // Allow rounding heuristic CbcRounding heuristic1(model); model.addHeuristic(&heuristic1); // And local search when new solution found CbcHeuristicLocal heuristic2(model); model.addHeuristic(&heuristic2); // Redundant definition of default branching (as Default == User) CbcBranchUserDecision branch; model.setBranchingMethod(&branch); // Definition of node choice CbcCompareUser compare; model.setNodeComparison(compare); // Do initial solve to continuous model.initialSolve(); // Could tune more model.setMinimumDrop(CoinMin(1.0, fabs(model.getMinimizationObjValue())*1.0e-3+1.0e-4)); if (model.getNumCols()<500) model.setMaximumCutPassesAtRoot(-100); // always do 100 if possible else if (model.getNumCols()<5000) model.setMaximumCutPassesAtRoot(100); // use minimum drop else model.setMaximumCutPassesAtRoot(20); //model.setMaximumCutPasses(5); // Switch off strong branching if wanted // model.setNumberStrong(0); // Do more strong branching if small if (model.getNumCols()<5000) model.setNumberStrong(10); model.solver()->setIntParam(OsiMaxNumIterationHotStart,100); // If time is given then stop after that number of minutes if (argc>2) { int minutes = atoi(argv[2]); std::cout<<"Stopping after "<<minutes<<" minutes"<<std::endl; assert (minutes>=0); model.setDblParam(CbcModel::CbcMaximumSeconds,60.0*minutes); } // Switch off most output if (model.getNumCols()<3000) { model.messageHandler()->setLogLevel(1); //model.solver()->messageHandler()->setLogLevel(0); } else { model.messageHandler()->setLogLevel(2); model.solver()->messageHandler()->setLogLevel(1); } double time1 = CoinCpuTime(); // Do complete search model.branchAndBound(); std::cout<<" Branch and cut took "<<CoinCpuTime()-time1<<" seconds, " <<model.getNodeCount()<<" nodes with objective " <<model.getObjValue() <<(!model.status() ? " Finished" : " Not finished") <<std::endl; // Print more statistics std::cout<<"Cuts at root node changed objective from "<<model.getContinuousObjective() <<" to "<<model.rootObjectiveAfterCuts()<<std::endl; int numberGenerators = model.numberCutGenerators(); for (int iGenerator=0;iGenerator<numberGenerators;iGenerator++) { CbcCutGenerator * generator = model.cutGenerator(iGenerator); std::cout<<generator->cutGeneratorName()<<" was tried " <<generator->numberTimesEntered()<<" times and created " <<generator->numberCutsInTotal()<<" cuts of which " <<generator->numberCutsActive()<<" were active after adding rounds of cuts" <<std::endl; } // Print solution if any - we can't get names from Osi! if (model.getMinimizationObjValue()<1.0e50) { int numberColumns = model.solver()->getNumCols(); const double * solution = model.solver()->getColSolution(); int iColumn; std::cout<<std::setiosflags(std::ios::fixed|std::ios::showpoint)<<std::setw(14); std::cout<<"--------------------------------------"<<std::endl; for (iColumn=0;iColumn<numberColumns;iColumn++) { double value=solution[iColumn]; if (fabs(value)>1.0e-7&&model.solver()->isInteger(iColumn)) std::cout<<std::setw(6)<<iColumn<<" "<<value<<std::endl; } std::cout<<"--------------------------------------"<<std::endl; std::cout<<std::resetiosflags(std::ios::fixed|std::ios::showpoint|std::ios::scientific); } return 0; }
void CglLandP::CachedData::getData(const OsiSolverInterface &si) { int nBasics = si.getNumRows(); int nNonBasics = si.getNumCols(); if (basis_ != NULL) delete basis_; basis_ = dynamic_cast<CoinWarmStartBasis *> (si.getWarmStart()); if (!basis_) throw NoBasisError(); if (nBasics_ > 0 || nBasics != nBasics_) { delete [] basics_; basics_ = NULL; } if (basics_ == NULL) { basics_ = new int[nBasics]; nBasics_ = nBasics; } if (nNonBasics_ > 0 || nNonBasics != nNonBasics_) { delete [] nonBasics_; nonBasics_ = NULL; } if (nonBasics_ == NULL) { nonBasics_ = new int[nNonBasics]; nNonBasics_ = nNonBasics; } int n = nBasics + nNonBasics; if ( nBasics_ + nNonBasics_ > 0 || nBasics_ + nNonBasics_ != n) { delete [] colsol_; delete [] integers_; integers_ = NULL; colsol_ = NULL; slacks_ = NULL; } if (colsol_ == NULL) { colsol_ = new double[n]; slacks_ = &colsol_[nNonBasics]; } if (integers_ == NULL) { integers_ = new bool[n]; } const double * rowLower = si.getRowLower(); const double * rowUpper = si.getRowUpper(); //determine which slacks are integer const CoinPackedMatrix * m = si.getMatrixByCol(); const double * elems = m->getElements(); const int * inds = m->getIndices(); const CoinBigIndex * starts = m->getVectorStarts(); const int * lengths = m->getVectorLengths(); // int numElems = m->getNumElements(); int numCols = m->getNumCols(); assert(numCols == nNonBasics_); // int numRows = m->getNumRows(); CoinFillN(integers_ ,n, true); for (int i = 0 ; i < numCols ; i++) { if (si.isContinuous(i)) integers_[i] = false; } bool * integerSlacks = integers_ + numCols; for (int i = 0 ; i < nBasics ; i++) { if (rowLower[i] > -1e50 && INT_INFEAS(rowLower[i]) > 1e-15) integerSlacks[i] = false; if (rowUpper[i] < 1e50 && INT_INFEAS(rowUpper[i]) > 1e-15) integerSlacks[i] = false; } for (int i = 0 ; i < numCols ; i++) { CoinBigIndex end = starts[i] + lengths[i]; if (integers_[i]) { for (CoinBigIndex k=starts[i] ; k < end; k++) { if (integerSlacks[inds[k]] && INT_INFEAS(elems[k])>1e-15 ) integerSlacks[inds[k]] = false; } } else { for (CoinBigIndex k=starts[i] ; k < end; k++) { if (integerSlacks[inds[k]]) integerSlacks[inds[k]] = false; } } } CoinCopyN(si.getColSolution(), si.getNumCols(), colsol_); CoinCopyN(si.getRowActivity(), si.getNumRows(), slacks_); for (int i = 0 ; i < si.getNumRows() ; i++) { slacks_[i]*=-1; if (rowLower[i]>-1e50) { slacks_[i] += rowLower[i]; } else { slacks_[i] += rowUpper[i]; } } //Now get the fill the arrays; nNonBasics = 0; nBasics = 0; //For having the index variables correctly ordered we need to access to OsiSimplexInterface { OsiSolverInterface * ncSi = (const_cast<OsiSolverInterface *>(&si)); ncSi->enableSimplexInterface(0); ncSi->getBasics(basics_); // Save enabled solver solver_ = si.clone(); #ifdef COIN_HAS_OSICLP OsiClpSolverInterface * clpSi = dynamic_cast<OsiClpSolverInterface *>(solver_); const OsiClpSolverInterface * clpSiRhs = dynamic_cast<const OsiClpSolverInterface *>(&si); if (clpSi) clpSi->getModelPtr()->copyEnabledStuff(clpSiRhs->getModelPtr());; #endif ncSi->disableSimplexInterface(); } int numStructural = basis_->getNumStructural(); for (int i = 0 ; i < numStructural ; i++) { if (basis_->getStructStatus(i)== CoinWarmStartBasis::basic) { nBasics++; //Basically do nothing } else { nonBasics_[nNonBasics++] = i; } } int numArtificial = basis_->getNumArtificial(); for (int i = 0 ; i < numArtificial ; i++) { if (basis_->getArtifStatus(i)== CoinWarmStartBasis::basic) { //Just check number of basics nBasics++; } else { nonBasics_[nNonBasics++] = i + basis_->getNumStructural(); } } }
int main (int argc, const char *argv[]) { // Define your favorite OsiSolver OsiClpSolverInterface solver1; // Read in model using argv[1] // and assert that it is a clean model std::string mpsFileName; #if defined(SAMPLEDIR) mpsFileName = SAMPLEDIR "/p0033.mps"; #else if (argc < 2) { fprintf(stderr, "Do not know where to find sample MPS files.\n"); exit(1); } #endif if (argc>=2) mpsFileName = argv[1]; int numMpsReadErrors = solver1.readMps(mpsFileName.c_str(),""); assert(numMpsReadErrors==0); double time1 = CoinCpuTime(); /* Options are: preprocess to do preprocessing time in minutes if 2 parameters and numeric taken as time */ bool preProcess=false; double minutes=-1.0; int nGoodParam=0; for (int iParam=2; iParam<argc;iParam++) { if (!strcmp(argv[iParam],"preprocess")) { preProcess=true; nGoodParam++; } else if (!strcmp(argv[iParam],"time")) { if (iParam+1<argc&&isdigit(argv[iParam+1][0])) { minutes=atof(argv[iParam+1]); if (minutes>=0.0) { nGoodParam+=2; iParam++; // skip time } } } } if (nGoodParam==0&&argc==3&&isdigit(argv[2][0])) { // If time is given then stop after that number of minutes minutes = atof(argv[2]); if (minutes>=0.0) nGoodParam=1; } if (nGoodParam!=argc-2&&argc>=2) { printf("Usage <file> [preprocess] [time <minutes>] or <file> <minutes>\n"); exit(1); } //solver1.getModelPtr()->setLogLevel(0); solver1.messageHandler()->setLogLevel(0); solver1.initialSolve(); // Reduce printout solver1.setHintParam(OsiDoReducePrint,true,OsiHintTry); CbcModel model(solver1); model.solver()->setHintParam(OsiDoReducePrint,true,OsiHintTry); // Set up some cut generators and defaults // Probing first as gets tight bounds on continuous CglProbing generator1; generator1.setUsingObjective(true); generator1.setMaxPass(1); generator1.setMaxPassRoot(5); // Number of unsatisfied variables to look at generator1.setMaxProbe(10); generator1.setMaxProbeRoot(1000); // How far to follow the consequences generator1.setMaxLook(50); generator1.setMaxLookRoot(500); // Only look at rows with fewer than this number of elements generator1.setMaxElements(200); generator1.setRowCuts(3); CglGomory generator2; // try larger limit generator2.setLimit(300); CglKnapsackCover generator3; CglRedSplit generator4; // try larger limit generator4.setLimit(200); CglClique generator5; generator5.setStarCliqueReport(false); generator5.setRowCliqueReport(false); CglMixedIntegerRounding2 mixedGen; CglFlowCover flowGen; // Add in generators // Experiment with -1 and -99 etc model.addCutGenerator(&generator1,-1,"Probing"); model.addCutGenerator(&generator2,-1,"Gomory"); model.addCutGenerator(&generator3,-1,"Knapsack"); // model.addCutGenerator(&generator4,-1,"RedSplit"); model.addCutGenerator(&generator5,-1,"Clique"); model.addCutGenerator(&flowGen,-1,"FlowCover"); model.addCutGenerator(&mixedGen,-1,"MixedIntegerRounding"); OsiClpSolverInterface * osiclp = dynamic_cast< OsiClpSolverInterface*> (model.solver()); // go faster stripes if (osiclp) { // Turn this off if you get problems // Used to be automatically set osiclp->setSpecialOptions(128); if(osiclp->getNumRows()<300&&osiclp->getNumCols()<500) { //osiclp->setupForRepeatedUse(2,1); osiclp->setupForRepeatedUse(0,1); } } // Uncommenting this should switch off most CBC messages //model.messagesPointer()->setDetailMessages(10,5,5000); // Allow rounding heuristic CbcRounding heuristic1(model); model.addHeuristic(&heuristic1); // And local search when new solution found CbcHeuristicLocal heuristic2(model); model.addHeuristic(&heuristic2); // Redundant definition of default branching (as Default == User) CbcBranchUserDecision branch; model.setBranchingMethod(&branch); // Definition of node choice CbcCompareUser compare; model.setNodeComparison(compare); // Do initial solve to continuous model.initialSolve(); // Could tune more double objValue = model.solver()->getObjSense()*model.solver()->getObjValue(); double minimumDropA=CoinMin(1.0,fabs(objValue)*1.0e-3+1.0e-4); double minimumDrop= fabs(objValue)*1.0e-4+1.0e-4; printf("min drop %g (A %g)\n",minimumDrop,minimumDropA); model.setMinimumDrop(minimumDrop); if (model.getNumCols()<500) model.setMaximumCutPassesAtRoot(-100); // always do 100 if possible else if (model.getNumCols()<5000) model.setMaximumCutPassesAtRoot(100); // use minimum drop else model.setMaximumCutPassesAtRoot(20); model.setMaximumCutPasses(10); //model.setMaximumCutPasses(2); // Switch off strong branching if wanted // model.setNumberStrong(0); // Do more strong branching if small if (model.getNumCols()<5000) model.setNumberStrong(10); model.setNumberStrong(20); //model.setNumberStrong(5); model.setNumberBeforeTrust(5); //model.setSizeMiniTree(2); model.solver()->setIntParam(OsiMaxNumIterationHotStart,100); // If time is given then stop after that number of minutes if (minutes>=0.0) { std::cout<<"Stopping after "<<minutes<<" minutes"<<std::endl; model.setDblParam(CbcModel::CbcMaximumSeconds,60.0*minutes); } // Switch off most output if (model.getNumCols()<3000) { model.messageHandler()->setLogLevel(1); //model.solver()->messageHandler()->setLogLevel(0); } else { model.messageHandler()->setLogLevel(2); model.solver()->messageHandler()->setLogLevel(1); } // Default strategy will leave cut generators as they exist already // so cutsOnlyAtRoot (1) ignored // numberStrong (2) is 5 (default) // numberBeforeTrust (3) is 5 (default is 0) // printLevel (4) defaults (0) CbcStrategyDefault strategy(true,5,5); // Set up pre-processing to find sos if wanted if (preProcess) strategy.setupPreProcessing(2); model.setStrategy(strategy); // Go round adding cuts to cutoff last solution // Stop after finding 20 best solutions for (int iPass=0;iPass<20;iPass++) { time1 = CoinCpuTime(); // Do complete search model.branchAndBound(); std::cout<<mpsFileName<<" took "<<CoinCpuTime()-time1<<" seconds, " <<model.getNodeCount()<<" nodes with objective " <<model.getObjValue() <<(!model.status() ? " Finished" : " Not finished") <<std::endl; // Stop if infeasible if (model.isProvenInfeasible()) break; // Print solution if finished - we can't get names from Osi! - so get from OsiClp assert (model.getMinimizationObjValue()<1.0e50); OsiSolverInterface * solver = model.solver(); int numberColumns = solver->getNumCols(); const double * solution = model.bestSolution(); //const double * lower = solver->getColLower(); //const double * upper = solver->getColUpper(); // Get names from solver1 (as OsiSolverInterface may lose) std::vector<std::string> columnNames = *solver1.getModelPtr()->columnNames(); int iColumn; std::cout<<std::setiosflags(std::ios::fixed|std::ios::showpoint)<<std::setw(14); std::cout<<"--------------------------------------"<<std::endl; for (iColumn=0;iColumn<numberColumns;iColumn++) { double value=solution[iColumn]; if (fabs(value)>1.0e-7&&solver->isInteger(iColumn)) std::cout<<std::setw(6)<<iColumn<<" " <<columnNames[iColumn]<<" " <<value //<<" "<<lower[iColumn]<<" "<<upper[iColumn] <<std::endl; } std::cout<<"--------------------------------------"<<std::endl; std::cout<<std::resetiosflags(std::ios::fixed|std::ios::showpoint|std::ios::scientific); /* Now add cut to reference copy. resetting to reference copy also gets rid of best solution so we should either save best solution, reset, add cut OR add cut to reference copy then reset - this is doing latter */ OsiSolverInterface * refSolver = model.referenceSolver(); const double * bestSolution = model.bestSolution(); const double * originalLower = refSolver->getColLower(); const double * originalUpper = refSolver->getColUpper(); CoinPackedVector cut; double rhs = 1.0; for (iColumn=0;iColumn<numberColumns;iColumn++) { double value=bestSolution[iColumn]; if (solver->isInteger(iColumn)) { // only works for 0-1 variables assert (originalLower[iColumn]==0.0&& originalUpper[iColumn]==1.0); // double check integer assert (fabs(floor(value+0.5)-value)<1.0e-5); if (value>0.5) { // at 1.0 cut.insert(iColumn,-1.0); rhs -= 1.0; } else { // at 0.0 cut.insert(iColumn,1.0); } } } // now add cut refSolver->addRow(cut,rhs,COIN_DBL_MAX); model.resetToReferenceSolver(); } return 0; }
int main (int argc, const char *argv[]) { // Define your favorite OsiSolver OsiClpSolverInterface solver1; // Read in model using argv[1] // and assert that it is a clean model std::string mpsFileName; #if defined(SAMPLEDIR) mpsFileName = SAMPLEDIR "/p0033.mps"; #else if (argc < 2) { fprintf(stderr, "Do not know where to find sample MPS files.\n"); exit(1); } #endif if (argc>=2) mpsFileName = argv[1]; int numMpsReadErrors = solver1.readMps(mpsFileName.c_str(),""); assert(numMpsReadErrors==0); double time1 = CoinCpuTime(); OsiClpSolverInterface solverSave = solver1; /* Options are: preprocess to do preprocessing time in minutes if 2 parameters and numeric taken as time */ bool preProcess=false; double minutes=-1.0; int nGoodParam=0; for (int iParam=2; iParam<argc;iParam++) { if (!strcmp(argv[iParam],"preprocess")) { preProcess=true; nGoodParam++; } else if (!strcmp(argv[iParam],"time")) { if (iParam+1<argc&&isdigit(argv[iParam+1][0])) { minutes=atof(argv[iParam+1]); if (minutes>=0.0) { nGoodParam+=2; iParam++; // skip time } } } } if (nGoodParam==0&&argc==3&&isdigit(argv[2][0])) { // If time is given then stop after that number of minutes minutes = atof(argv[2]); if (minutes>=0.0) nGoodParam=1; } if (nGoodParam!=argc-2&&argc>=2) { printf("Usage <file> [preprocess] [time <minutes>] or <file> <minutes>\n"); exit(1); } // Reduce printout solver1.setHintParam(OsiDoReducePrint,true,OsiHintTry); // See if we want preprocessing OsiSolverInterface * solver2=&solver1; CglPreProcess process; // Never do preprocessing until dual tests out as can fix incorrectly preProcess=false; if (preProcess) { /* Do not try and produce equality cliques and do up to 5 passes */ solver2 = process.preProcess(solver1,false,5); if (!solver2) { printf("Pre-processing says infeasible\n"); exit(2); } solver2->resolve(); } // Turn L rows into cuts CglStoredUser stored; { int numberRows = solver2->getNumRows(); int * whichRow = new int[numberRows]; // get row copy const CoinPackedMatrix * rowCopy = solver2->getMatrixByRow(); const int * column = rowCopy->getIndices(); const int * rowLength = rowCopy->getVectorLengths(); const CoinBigIndex * rowStart = rowCopy->getVectorStarts(); const double * rowLower = solver2->getRowLower(); const double * rowUpper = solver2->getRowUpper(); const double * element = rowCopy->getElements(); int iRow,nDelete=0; for (iRow=0;iRow<numberRows;iRow++) { if (rowLower[iRow]<-1.0e20||rowUpper[iRow]>1.0e20) { // take out whichRow[nDelete++]=iRow; } } // leave some rows to avoid empty problem (Gomory does not like) nDelete = CoinMax(CoinMin(nDelete,numberRows-5),0); for (int jRow=0;jRow<nDelete;jRow++) { iRow=whichRow[jRow]; int start = rowStart[iRow]; stored.addCut(rowLower[iRow],rowUpper[iRow],rowLength[iRow], column+start,element+start); } /* The following is problem specific. Normally cuts are deleted if slack on cut basic. On some problems you may wish to leave cuts in as long as slack value zero */ int numberCuts=stored.sizeRowCuts(); for (int iCut=0;iCut<numberCuts;iCut++) { //stored.mutableRowCutPointer(iCut)->setEffectiveness(1.0e50); } solver2->deleteRows(nDelete,whichRow); delete [] whichRow; } CbcModel model(*solver2); model.solver()->setHintParam(OsiDoReducePrint,true,OsiHintTry); // Set up some cut generators and defaults // Probing first as gets tight bounds on continuous CglProbing generator1; generator1.setUsingObjective(true); generator1.setMaxPass(1); generator1.setMaxPassRoot(5); // Number of unsatisfied variables to look at generator1.setMaxProbe(10); generator1.setMaxProbeRoot(1000); // How far to follow the consequences generator1.setMaxLook(50); generator1.setMaxLookRoot(500); // Only look at rows with fewer than this number of elements generator1.setMaxElements(200); generator1.setRowCuts(3); CglGomory generator2; // try larger limit generator2.setLimit(300); CglKnapsackCover generator3; CglRedSplit generator4; // try larger limit generator4.setLimit(200); CglClique generator5; generator5.setStarCliqueReport(false); generator5.setRowCliqueReport(false); CglMixedIntegerRounding2 mixedGen; CglFlowCover flowGen; // Add in generators // Experiment with -1 and -99 etc // This is just for one particular model model.addCutGenerator(&generator1,-1,"Probing"); //model.addCutGenerator(&generator2,-1,"Gomory"); model.addCutGenerator(&generator2,1,"Gomory"); model.addCutGenerator(&generator3,-1,"Knapsack"); // model.addCutGenerator(&generator4,-1,"RedSplit"); //model.addCutGenerator(&generator5,-1,"Clique"); model.addCutGenerator(&generator5,1,"Clique"); model.addCutGenerator(&flowGen,-1,"FlowCover"); model.addCutGenerator(&mixedGen,-1,"MixedIntegerRounding"); // Add stored cuts (making sure at all depths) model.addCutGenerator(&stored,1,"Stored",true,false,false,-100,1,-1); int numberGenerators = model.numberCutGenerators(); int iGenerator; // Say we want timings for (iGenerator=0;iGenerator<numberGenerators;iGenerator++) { CbcCutGenerator * generator = model.cutGenerator(iGenerator); generator->setTiming(true); } OsiClpSolverInterface * osiclp = dynamic_cast< OsiClpSolverInterface*> (model.solver()); // go faster stripes if (osiclp) { if(osiclp->getNumRows()<300&&osiclp->getNumCols()<500) { //osiclp->setupForRepeatedUse(2,0); osiclp->setupForRepeatedUse(0,0); } // Don't allow dual stuff osiclp->setSpecialOptions(osiclp->specialOptions()|262144); } // Uncommenting this should switch off all CBC messages // model.messagesPointer()->setDetailMessages(10,10000,NULL); // No heuristics // Do initial solve to continuous model.initialSolve(); /* You need the next few lines - a) so that cut generator will always be called again if it generated cuts b) it is known that matrix is not enough to define problem so do cuts even if it looks integer feasible at continuous optimum. c) a solution found by strong branching will be ignored. d) don't recompute a solution once found */ // Make sure cut generator called correctly (a) iGenerator=numberGenerators-1; model.cutGenerator(iGenerator)->setMustCallAgain(true); // Say cuts needed at continuous (b) OsiBabSolver oddCuts; oddCuts.setSolverType(4); // owing to bug must set after initialSolve model.passInSolverCharacteristics(&oddCuts); // Say no to all solutions by strong branching (c) CbcFeasibilityNoStrong noStrong; model.setProblemFeasibility(noStrong); // Say don't recompute solution d) model.setSpecialOptions(4); // Could tune more double objValue = model.solver()->getObjSense()*model.solver()->getObjValue(); double minimumDropA=CoinMin(1.0,fabs(objValue)*1.0e-3+1.0e-4); double minimumDrop= fabs(objValue)*1.0e-4+1.0e-4; printf("min drop %g (A %g)\n",minimumDrop,minimumDropA); model.setMinimumDrop(minimumDrop); if (model.getNumCols()<500) model.setMaximumCutPassesAtRoot(-100); // always do 100 if possible else if (model.getNumCols()<5000) model.setMaximumCutPassesAtRoot(100); // use minimum drop else model.setMaximumCutPassesAtRoot(20); model.setMaximumCutPasses(10); //model.setMaximumCutPasses(2); // Switch off strong branching if wanted // model.setNumberStrong(0); // Do more strong branching if small if (model.getNumCols()<5000) model.setNumberStrong(10); model.setNumberStrong(20); //model.setNumberStrong(5); model.setNumberBeforeTrust(5); model.solver()->setIntParam(OsiMaxNumIterationHotStart,100); // If time is given then stop after that number of minutes if (minutes>=0.0) { std::cout<<"Stopping after "<<minutes<<" minutes"<<std::endl; model.setDblParam(CbcModel::CbcMaximumSeconds,60.0*minutes); } // Switch off most output if (model.getNumCols()<30000) { model.messageHandler()->setLogLevel(1); //model.solver()->messageHandler()->setLogLevel(0); } else { model.messageHandler()->setLogLevel(2); model.solver()->messageHandler()->setLogLevel(1); } //model.messageHandler()->setLogLevel(2); //model.solver()->messageHandler()->setLogLevel(2); //model.setPrintFrequency(50); //#define DEBUG_CUTS #ifdef DEBUG_CUTS // Set up debugger by name (only if no preprocesing) if (!preProcess) { std::string problemName ; model.solver()->getStrParam(OsiProbName,problemName) ; model.solver()->activateRowCutDebugger(problemName.c_str()) ; } #endif // Do complete search model.branchAndBound(); std::cout<<mpsFileName<<" took "<<CoinCpuTime()-time1<<" seconds, " <<model.getNodeCount()<<" nodes with objective " <<model.getObjValue() <<(!model.status() ? " Finished" : " Not finished") <<std::endl; // Print more statistics std::cout<<"Cuts at root node changed objective from "<<model.getContinuousObjective() <<" to "<<model.rootObjectiveAfterCuts()<<std::endl; for (iGenerator=0;iGenerator<numberGenerators;iGenerator++) { CbcCutGenerator * generator = model.cutGenerator(iGenerator); std::cout<<generator->cutGeneratorName()<<" was tried " <<generator->numberTimesEntered()<<" times and created " <<generator->numberCutsInTotal()<<" cuts of which " <<generator->numberCutsActive()<<" were active after adding rounds of cuts"; if (generator->timing()) std::cout<<" ( "<<generator->timeInCutGenerator()<<" seconds)"<<std::endl; else std::cout<<std::endl; } // Print solution if finished - we can't get names from Osi! - so get from OsiClp if (model.getMinimizationObjValue()<1.0e50) { // post process OsiSolverInterface * solver; if (preProcess) { process.postProcess(*model.solver()); // Solution now back in solver1 solver = & solver1; } else { solver = model.solver(); } int numberColumns = solver->getNumCols(); const double * solution = solver->getColSolution(); // Get names from solver1 (as OsiSolverInterface may lose) std::vector<std::string> columnNames = *solver1.getModelPtr()->columnNames(); int iColumn; std::cout<<std::setiosflags(std::ios::fixed|std::ios::showpoint)<<std::setw(14); std::cout<<"--------------------------------------"<<std::endl; for (iColumn=0;iColumn<numberColumns;iColumn++) { double value=solution[iColumn]; if (fabs(value)>1.0e-7&&solver->isInteger(iColumn)) { std::cout<<std::setw(6)<<iColumn<<" " <<columnNames[iColumn]<<" " <<value<<std::endl; solverSave.setColLower(iColumn,value); solverSave.setColUpper(iColumn,value); } } std::cout<<"--------------------------------------"<<std::endl; std::cout<<std::resetiosflags(std::ios::fixed|std::ios::showpoint|std::ios::scientific); solverSave.initialSolve(); } return 0; }
int main(int argc, char **argv) { char *f_name_lp, *last_dot_pos, f_name[256], *f_name_pos; int i, ncol; if((argc < 2) || (argc > 2)) { printf("### ERROR: main(): Usage: One of the following\ncgl_data_test input_file_name.mps\ncgl_data_test input_file_name.lp\n"); exit(1); } f_name_lp = strdup(argv[1]); f_name_pos = strrchr(f_name_lp, '/'); if(f_name_pos != NULL) { strcpy(f_name, &(f_name_pos[1])); } else { strcpy(f_name, f_name_lp); } last_dot_pos = strrchr(f_name, '.'); if(last_dot_pos != NULL) { last_dot_pos = '\0'; } OsiClpSolverInterface *clp = new OsiClpSolverInterface; clp->messageHandler()->setLogLevel(0); if(strcmp(&(f_name_lp[strlen(f_name_lp)-3]), ".lp") == 0) { clp->readLp(f_name_lp); } else { if(strcmp(&(f_name_lp[strlen(f_name_lp)-4]), ".mps") == 0) { clp->readMps(f_name_lp); } else { printf("### ERROR: unrecognized file type\n"); exit(1); } } ncol = clp->getNumCols(); clp->initialSolve(); printf("LP value: %12.2f\n", clp->getObjValue()); OsiCuts cuts; // Define parameters for CglRedSplit generator CglParam cpar; cpar.setMAX_SUPPORT(ncol+1); CglRedSplitParam rspar(cpar); // Create a cut generator with the given parameters CglRedSplit cutGen(rspar); char *colType = new char[ncol]; for(i=0; i<ncol; i++) { if(clp->isContinuous(i)) { colType[i] = 'C'; } else { colType[i] = 'I'; } } int round, max_rounds = 10; for(round=0; round<max_rounds; round++) { cutGen.generateCuts(*clp, cuts); int ncuts = cuts.sizeRowCuts(); const OsiRowCut **newRowCuts = new const OsiRowCut * [ncuts]; for(i=0; i<ncuts; i++) { newRowCuts[i] = &cuts.rowCut(i); } clp->applyRowCuts(ncuts, newRowCuts); delete[] newRowCuts; printf("round %4d: %4d generated cuts new objective value: %12.2f\n", round, ncuts, clp->getObjValue()); clp->resolve(); if(clp->isAbandoned()) { printf("###ERROR: Numerical difficulties in Solver\n"); exit(1); } if(clp->isProvenPrimalInfeasible()) { printf("### WARNING: Problem is infeasible\n"); exit(1); } } delete clp; free(f_name_lp); delete[] colType; return(0); }
/* Randomized Rounding Heuristic Returns 1 if solution, 0 if not */ int CbcHeuristicRandRound::solution(double & solutionValue, double * betterSolution) { // rlh: Todo: Memory Cleanup // std::cout << "Entering the Randomized Rounding Heuristic" << std::endl; setWhen(1); // setWhen(1) didn't have the effect I expected (e.g., run once). // Run only once. // // See if at root node bool atRoot = model_->getNodeCount() == 0; int passNumber = model_->getCurrentPassNumber(); // Just do once if (!atRoot || passNumber > 1) { // std::cout << "Leaving the Randomized Rounding Heuristic" << std::endl; return 0; } std::cout << "Entering the Randomized Rounding Heuristic" << std::endl; typedef struct { int numberSolutions; int maximumSolutions; int numberColumns; double ** solution; int * numberUnsatisfied; } clpSolution; double start = CoinCpuTime(); numCouldRun_++; // #ifdef HEURISTIC_INFORM printf("Entering heuristic %s - nRuns %d numCould %d when %d\n", heuristicName(),numRuns_,numCouldRun_,when_); #endif // Todo: Ask JJHF what "number of times // the heuristic could run" means. OsiSolverInterface * solver = model_->solver()->clone(); double primalTolerance ; solver->getDblParam(OsiPrimalTolerance, primalTolerance) ; OsiClpSolverInterface * clpSolver = dynamic_cast<OsiClpSolverInterface *> (solver); assert (clpSolver); ClpSimplex * simplex = clpSolver->getModelPtr(); // Initialize the structure holding the solutions for the Simplex iterations clpSolution solutions; // Set typeStruct field of ClpTrustedData struct to 1 to indicate // desired behavior for RandRound heuristic (which is what?) ClpTrustedData trustedSolutions; trustedSolutions.typeStruct = 1; trustedSolutions.data = &solutions; solutions.numberSolutions = 0; solutions.maximumSolutions = 0; solutions.numberColumns = simplex->numberColumns(); solutions.solution = NULL; solutions.numberUnsatisfied = NULL; simplex->setTrustedUserPointer(&trustedSolutions); // Solve from all slack to get some points simplex->allSlackBasis(); // Calling primal() invalidates pointers to some rim vectors, // like...row sense (!) simplex->primal(); // 1. Okay - so a workaround would be to copy the data I want BEFORE // calling primal. // 2. Another approach is to ask the simplex solvers NOT to mess up my // rims. // 3. See freeCachedResults() for what is getting // deleted. Everything else points into the structure. // ...or use collower and colupper rather than rowsense. // ..store address of where one of these // Store the basic problem information // -Get the number of columns, rows and rhs vector int numCols = clpSolver->getNumCols(); int numRows = clpSolver->getNumRows(); // Find the integer variables (use columnType(?)) // One if not continuous, that is binary or general integer) // columnType() = 0 continuous // = 1 binary // = 2 general integer bool * varClassInt = new bool[numCols]; const char* columnType = clpSolver->columnType(); int numGenInt = 0; for (int i = 0; i < numCols; i++) { if (clpSolver->isContinuous(i)) varClassInt[i] = 0; else varClassInt[i] = 1; if (columnType[i] == 2) numGenInt++; } // Heuristic is for problems with general integer variables. // If there are none, quit. if (numGenInt++ < 1) { delete [] varClassInt ; std::cout << "Leaving the Randomized Rounding Heuristic" << std::endl; return 0; } // -Get the rows sense const char * rowSense; rowSense = clpSolver->getRowSense(); // -Get the objective coefficients double *originalObjCoeff = CoinCopyOfArray(clpSolver->getObjCoefficients(), numCols); // -Get the matrix of the problem // rlh: look at using sparse representation double ** matrix = new double * [numRows]; for (int i = 0; i < numRows; i++) { matrix[i] = new double[numCols]; for (int j = 0; j < numCols; j++) matrix[i][j] = 0; } const CoinPackedMatrix* matrixByRow = clpSolver->getMatrixByRow(); const double * matrixElements = matrixByRow->getElements(); const int * matrixIndices = matrixByRow->getIndices(); const int * matrixStarts = matrixByRow->getVectorStarts(); for (int j = 0; j < numRows; j++) { for (int i = matrixStarts[j]; i < matrixStarts[j+1]; i++) { matrix[j][matrixIndices[i]] = matrixElements[i]; } } double * newObj = new double [numCols]; srand ( static_cast<unsigned int>(time(NULL) + 1)); int randNum; // Shuffle the rows: // Put the rows in a random order // so that the optimal solution is a different corner point than the // starting point. int * index = new int [numRows]; for (int i = 0; i < numRows; i++) index[i] = i; for (int i = 0; i < numRows; i++) { int temp = index[i]; int randNumTemp = i + intRand(numRows - i); index[i] = index[randNumTemp]; index[randNumTemp] = temp; } // Start finding corner points by iteratively doing the following: // - contruct a randomly tilted objective // - solve for (int i = 0; i < numRows; i++) { // TODO: that 10,000 could be a param in the member data if (solutions.numberSolutions > 10000) break; randNum = intRand(2); for (int j = 0; j < numCols; j++) { // for row i and column j vary the coefficient "a bit" if (randNum == 1) // if the element is zero, then set the new obj // coefficient to 0.1 (i.e., round up) if (fabs(matrix[index[i]][j]) < primalTolerance) newObj[j] = 0.1; else // if the element is nonzero, then increase the new obj // coefficient "a bit" newObj[j] = matrix[index[i]][j] * 1.1; else // if randnum is 2, then // if the element is zero, then set the new obj coeffient // to NEGATIVE 0.1 (i.e., round down) if (fabs(matrix[index[i]][j]) < primalTolerance) newObj[j] = -0.1; else // if the element is nonzero, then DEcrease the new obj coeffienct "a bit" newObj[j] = matrix[index[i]][j] * 0.9; } // Use the new "tilted" objective clpSolver->setObjective(newObj); // Based on the row sense, we decide whether to max or min if (rowSense[i] == 'L') clpSolver->setObjSense(-1); else clpSolver->setObjSense(1); // Solve with primal simplex simplex->primal(1); // rlh+ll: This was the original code. But we already have the // model pointer (it's in simplex). And, calling getModelPtr() // invalidates the cached data in the OsiClpSolverInterface // object, which means our precious rowsens is lost. So let's // not use the line below... /******* clpSolver->getModelPtr()->primal(1); */ printf("---------------------------------------------------------------- %d\n", i); } // Iteratively do this process until... // either you reach the max number of corner points (aka 10K) // or all the rows have been used as an objective. // Look at solutions int numberSolutions = solutions.numberSolutions; //const char * integerInfo = simplex->integerInformation(); //const double * columnLower = simplex->columnLower(); //const double * columnUpper = simplex->columnUpper(); printf("there are %d solutions\n", numberSolutions); // Up to here we have all the corner points // Now we need to do the random walks and roundings double ** cornerPoints = new double * [numberSolutions]; for (int j = 0; j < numberSolutions; j++) cornerPoints[j] = solutions.solution[j]; bool feasibility = 1; // rlh: use some COIN max instead of 1e30 (?) double bestObj = 1e30; std::vector< std::vector <double> > feasibles; int numFeasibles = 0; // Check the feasibility of the corner points int numCornerPoints = numberSolutions; const double * rhs = clpSolver->getRightHandSide(); // rlh: row sense hasn't changed. why a fresh copy? // Delete next line. rowSense = clpSolver->getRowSense(); for (int i = 0; i < numCornerPoints; i++) { //get the objective value for this this point double objValue = 0; for (int k = 0; k < numCols; k++) objValue += cornerPoints[i][k] * originalObjCoeff[k]; if (objValue < bestObj) { // check integer feasibility feasibility = 1; for (int j = 0; j < numCols; j++) { if (varClassInt[j]) { double closest = floor(cornerPoints[i][j] + 0.5); if (fabs(cornerPoints[i][j] - closest) > primalTolerance) { feasibility = 0; break; } } } // check all constraints satisfied if (feasibility) { for (int irow = 0; irow < numRows; irow++) { double lhs = 0; for (int j = 0; j < numCols; j++) { lhs += matrix[irow][j] * cornerPoints[i][j]; } if (rowSense[irow] == 'L' && lhs > rhs[irow] + primalTolerance) { feasibility = 0; break; } if (rowSense[irow] == 'G' && lhs < rhs[irow] - primalTolerance) { feasibility = 0; break; } if (rowSense[irow] == 'E' && (lhs - rhs[irow] > primalTolerance || lhs - rhs[irow] < -primalTolerance)) { feasibility = 0; break; } } } if (feasibility) { numFeasibles++; feasibles.push_back(std::vector <double> (numCols)); for (int k = 0; k < numCols; k++) feasibles[numFeasibles-1][k] = cornerPoints[i][k]; printf("obj: %f\n", objValue); if (objValue < bestObj) bestObj = objValue; } } } int numFeasibleCorners; numFeasibleCorners = numFeasibles; //find the center of gravity of the corner points as the first random point double * rp = new double[numCols]; for (int i = 0; i < numCols; i++) { rp[i] = 0; for (int j = 0; j < numCornerPoints; j++) { rp[i] += cornerPoints[j][i]; } rp[i] = rp[i] / numCornerPoints; } //------------------------------------------- //main loop: // -generate the next random point // -round the random point // -check the feasibility of the random point //------------------------------------------- srand ( static_cast<unsigned int>(time(NULL) + 1)); int numRandomPoints = 0; while (numRandomPoints < 50000) { numRandomPoints++; //generate the next random point int randomIndex = intRand(numCornerPoints); double random = CoinDrand48(); for (int i = 0; i < numCols; i++) { rp[i] = (random * (cornerPoints[randomIndex][i] - rp[i])) + rp[i]; } //CRISP ROUNDING //round the random point just generated double * roundRp = new double[numCols]; for (int i = 0; i < numCols; i++) { roundRp[i] = rp[i]; if (varClassInt[i]) { if (rp[i] >= 0) { if (fmod(rp[i], 1) > 0.5) roundRp[i] = floor(rp[i]) + 1; else roundRp[i] = floor(rp[i]); } else { if (fabs(fmod(rp[i], 1)) > 0.5) roundRp[i] = floor(rp[i]); else roundRp[i] = floor(rp[i]) + 1; } } } //SOFT ROUNDING // Look at original files for the "how to" on soft rounding; // Soft rounding omitted here. //Check the feasibility of the rounded random point // -Check the feasibility // -Get the rows sense rowSense = clpSolver->getRowSense(); rhs = clpSolver->getRightHandSide(); //get the objective value for this feasible point double objValue = 0; for (int i = 0; i < numCols; i++) objValue += roundRp[i] * originalObjCoeff[i]; if (objValue < bestObj) { feasibility = 1; for (int i = 0; i < numRows; i++) { double lhs = 0; for (int j = 0; j < numCols; j++) { lhs += matrix[i][j] * roundRp[j]; } if (rowSense[i] == 'L' && lhs > rhs[i] + primalTolerance) { feasibility = 0; break; } if (rowSense[i] == 'G' && lhs < rhs[i] - primalTolerance) { feasibility = 0; break; } if (rowSense[i] == 'E' && (lhs - rhs[i] > primalTolerance || lhs - rhs[i] < -primalTolerance)) { feasibility = 0; break; } } if (feasibility) { printf("Feasible Found.\n"); printf("%.2f\n", CoinCpuTime() - start); numFeasibles++; feasibles.push_back(std::vector <double> (numCols)); for (int i = 0; i < numCols; i++) feasibles[numFeasibles-1][i] = roundRp[i]; printf("obj: %f\n", objValue); if (objValue < bestObj) bestObj = objValue; } } delete [] roundRp; } printf("Number of Feasible Corners: %d\n", numFeasibleCorners); printf("Number of Feasibles Found: %d\n", numFeasibles); if (numFeasibles > 0) printf("Best Objective: %f\n", bestObj); printf("time: %.2f\n", CoinCpuTime() - start); if (numFeasibles == 0) { // cleanup delete [] varClassInt; for (int i = 0; i < numRows; i++) delete matrix[i]; delete [] matrix; delete [] newObj; delete [] index; for (int i = 0; i < numberSolutions; i++) delete cornerPoints[i]; delete [] cornerPoints; delete [] rp; return 0; } // We found something better solutionValue = bestObj; for (int k = 0; k < numCols; k++) { betterSolution[k] = feasibles[numFeasibles-1][k]; } delete [] varClassInt; for (int i = 0; i < numRows; i++) delete matrix[i]; delete [] matrix; delete [] newObj; delete [] index; for (int i = 0; i < numberSolutions; i++) delete cornerPoints[i]; delete [] cornerPoints; delete [] rp; std::cout << "Leaving the Randomized Rounding Heuristic" << std::endl; return 1; }
int main( int argc, char **argv ) { if ( argc < 2 ) { printf("Invalid number of parameters!\n"); exit( EXIT_FAILURE ); } char problemName[ 256 ]; getFileName( problemName, argv[1] ); clock_t start = clock(); OsiClpSolverInterface *realSolver = new OsiClpSolverInterface(); realSolver->getModelPtr()->setPerturbation(50); /* makes CLP faster for hard instances */ OsiSolverInterface *solver = (OsiSolverInterface*) realSolver; parseParameters( argc, argv ); readLP( solver, argv[1] ); FILE *log = NULL; if(!output.empty()) { log = fopen(output.c_str(), "a"); if(!log) { printf("Could not open the file!\n"); exit(EXIT_FAILURE); } } const int numCols = solver->getNumCols(), numRows = solver->getNumRows(); int pass = 0, newCuts = 0, totalCuts = 0; double pTime, opt, cgTime; CGraph *cgraph = NULL; if(sepMethod == Npsep) cgraph = build_cgraph_osi( solver ); if(!optFile.empty()) { getOptimals(); if(optimals.find(problemName) == optimals.end()) { fprintf(stderr, "ERROR: optimal value not found!\n"); exit(EXIT_FAILURE); } opt = optimals[problemName]; } solver->initialSolve(); if (!solver->isProvenOptimal()) { if (solver->isAbandoned()) { fprintf( stderr, "LP solver abandoned due to numerical dificulties.\n" ); exit( EXIT_FAILURE ); } if (solver->isProvenPrimalInfeasible()) { fprintf( stderr, "LP solver says PRIMAL INFEASIBLE.\n" ); exit( EXIT_FAILURE ); } if (solver->isProvenDualInfeasible()) { fprintf( stderr, "LP solver says DUAL INFEASIBLE.\n" ); exit( EXIT_FAILURE ); } if (solver->isPrimalObjectiveLimitReached()) { fprintf( stderr, "LP solver says isPrimalObjectiveLimitReached.\n" ); exit( EXIT_FAILURE ); } if (solver->isDualObjectiveLimitReached()) { fprintf( stderr, "LP solver says isDualObjectiveLimitReached.\n" ); exit( EXIT_FAILURE ); } if (solver->isIterationLimitReached()) { fprintf( stderr, "LP solver says isIterationLimitReached.\n" ); exit( EXIT_FAILURE ); } fprintf( stderr, "ERROR: Could not solve LP relaxation to optimality. Checking status...\n" ); exit( EXIT_FAILURE ); } double initialBound = solver->getObjValue(); printf("%.2lf %d %d %.7lf", ((double)(clock()-start)) / ((double)CLOCKS_PER_SEC), pass, 0, solver->getObjValue()); if(!optFile.empty()) { printf(" %.7lf %.7lf", opt, abs_mip_gap(solver->getObjValue(), opt)); } printf("\n"); do { clock_t startSep = clock(); newCuts = 0; switch (sepMethod) { case Npsep: { CglEClique cliqueGen; OsiCuts cuts; CglTreeInfo info; info.level = 0; info.pass = 1; vector<string> varNames = getVarNames(solver->getColNames(), numCols); cliqueGen.parseParameters( argc, (const char**)argv ); cliqueGen.setCGraph( cgraph ); cliqueGen.setGenOddHoles( true ); //allow (or not) inserting odd hole cuts cliqueGen.colNames = &varNames; cliqueGen.generateCuts( *solver, cuts, info ); newCuts = cuts.sizeCuts(); solver->applyCuts( cuts ); } break; case CglSepM: { CglClique cliqueGen; OsiCuts cuts; CglTreeInfo info; info.level = 0; info.pass = 1; cliqueGen.setMinViolation( MIN_VIOLATION ); cliqueGen.setStarCliqueReport(false); cliqueGen.setRowCliqueReport(false); cliqueGen.generateCuts( *solver, cuts, info ); newCuts = cuts.sizeCuts(); solver->applyCuts( cuts ); } break; Default: { fprintf( stderr, "Separation Method does not recognized!\n" ); exit( EXIT_FAILURE ); } } pTime = ((double)(clock()-start)) / ((double)CLOCKS_PER_SEC); if(pTime > MAX_TIME) break; totalCuts += newCuts; ++pass; if (newCuts) { solver->resolve(); if (!solver->isProvenOptimal()) { if (solver->isAbandoned()) { fprintf( stderr, "LP solver abandoned due to numerical dificulties.\n" ); exit( EXIT_FAILURE ); } if (solver->isProvenPrimalInfeasible()) { fprintf( stderr, "LP solver says PRIMAL INFEASIBLE.\n" ); exit( EXIT_FAILURE ); } if (solver->isProvenDualInfeasible()) { fprintf( stderr, "LP solver says DUAL INFEASIBLE.\n" ); exit( EXIT_FAILURE ); } if (solver->isPrimalObjectiveLimitReached()) { fprintf( stderr, "LP solver says isPrimalObjectiveLimitReached.\n" ); exit( EXIT_FAILURE ); } if (solver->isDualObjectiveLimitReached()) { fprintf( stderr, "LP solver says isDualObjectiveLimitReached.\n" ); exit( EXIT_FAILURE ); } if (solver->isIterationLimitReached()) { fprintf( stderr, "LP solver says isIterationLimitReached.\n" ); exit( EXIT_FAILURE ); } fprintf( stderr, "ERROR: Could not solve LP relaxation. Exiting.\n" ); exit( EXIT_FAILURE ); } pTime = ((double)(clock()-start)) / ((double)CLOCKS_PER_SEC); if(pTime > MAX_TIME) break; double sepTime = ((double)(clock()-startSep)) / ((double)CLOCKS_PER_SEC); printf("%.2lf %d %d %.7lf", sepTime, pass, newCuts, solver->getObjValue()); if(!optFile.empty()) printf(" %.7lf %.7lf", opt, abs_mip_gap(solver->getObjValue(), opt)); printf("\n"); } } while ( (newCuts>0) && (pass<MAX_PASSES) ) ; if(log) { double totalTime = ((double)(clock()-start)) / ((double)CLOCKS_PER_SEC); fprintf(log, "%s %.2lf %d %d %.7lf", problemName, totalTime, pass - 1, totalCuts, solver->getObjValue()); if(!optFile.empty()) fprintf(log, " %.7lf", abs_mip_gap(solver->getObjValue(), opt)); fprintf(log, "\n"); } if(cgraph) cgraph_free( &cgraph ); delete realSolver; return EXIT_SUCCESS; }
// Apply subproblem void CbcSubProblem::apply(OsiSolverInterface * solver, int what) const { int i; if ((what&1) != 0) { #ifndef NDEBUG int nSame = 0; #endif for (i = 0; i < numberChangedBounds_; i++) { int variable = variables_[i]; int k = variable & 0x3fffffff; if ((variable&0x80000000) == 0) { // lower bound changing //#define CBC_PRINT2 #ifdef CBC_PRINT2 if (solver->getColLower()[k] != newBounds_[i]) printf("lower change for column %d - from %g to %g\n", k, solver->getColLower()[k], newBounds_[i]); #endif #ifndef NDEBUG if ((variable&0x40000000) == 0 && true) { double oldValue = solver->getColLower()[k]; assert (newBounds_[i] > oldValue - 1.0e-8); if (newBounds_[i] < oldValue + 1.0e-8) { #ifdef CBC_PRINT2 printf("bad null lower change for column %d - bound %g\n", k, oldValue); #endif if (newBounds_[i] == oldValue) nSame++; } } #endif solver->setColLower(k, newBounds_[i]); } else { // upper bound changing #ifdef CBC_PRINT2 if (solver->getColUpper()[k] != newBounds_[i]) printf("upper change for column %d - from %g to %g\n", k, solver->getColUpper()[k], newBounds_[i]); #endif #ifndef NDEBUG if ((variable&0x40000000) == 0 && true) { double oldValue = solver->getColUpper()[k]; assert (newBounds_[i] < oldValue + 1.0e-8); if (newBounds_[i] > oldValue - 1.0e-8) { #ifdef CBC_PRINT2 printf("bad null upper change for column %d - bound %g\n", k, oldValue); #endif if (newBounds_[i] == oldValue) nSame++; } } #endif solver->setColUpper(k, newBounds_[i]); } } #ifndef NDEBUG #ifdef CBC_PRINT2 if (nSame && (nSame < numberChangedBounds_ || (what&3) != 3)) printf("%d changes out of %d redundant %d\n", nSame, numberChangedBounds_, what); else if (numberChangedBounds_ && what == 7 && !nSame) printf("%d good changes %d\n", numberChangedBounds_, what); #endif #endif } #ifdef JJF_ZERO if ((what&2) != 0) { OsiClpSolverInterface * clpSolver = dynamic_cast<OsiClpSolverInterface *> (solver); assert (clpSolver); //assert (clpSolver->getNumRows()==numberRows_); //clpSolver->setBasis(*status_); // Current basis CoinWarmStartBasis * basis = clpSolver->getPointerToWarmStart(); printf("BBBB\n"); basis->print(); assert (basis->fullBasis()); basis->applyDiff(status_); printf("diff applied %x\n", status_); printf("CCCC\n"); basis->print(); assert (basis->fullBasis()); #ifndef NDEBUG if (!basis->fullBasis()) printf("Debug this basis!!\n"); #endif clpSolver->setBasis(*basis); } #endif if ((what&8) != 0) { OsiClpSolverInterface * clpSolver = dynamic_cast<OsiClpSolverInterface *> (solver); assert (clpSolver); clpSolver->setBasis(*status_); delete status_; status_ = NULL; } }
// inner part of dive int CbcHeuristicDive::solution(double & solutionValue, int & numberNodes, int & numberCuts, OsiRowCut ** cuts, CbcSubProblem ** & nodes, double * newSolution) { #ifdef DIVE_DEBUG int nRoundInfeasible = 0; int nRoundFeasible = 0; #endif int reasonToStop = 0; double time1 = CoinCpuTime(); int numberSimplexIterations = 0; int maxSimplexIterations = (model_->getNodeCount()) ? maxSimplexIterations_ : maxSimplexIterationsAtRoot_; // but can't be exactly coin_int_max maxSimplexIterations = CoinMin(maxSimplexIterations,COIN_INT_MAX>>3); OsiSolverInterface * solver = cloneBut(6); // was model_->solver()->clone(); # ifdef COIN_HAS_CLP OsiClpSolverInterface * clpSolver = dynamic_cast<OsiClpSolverInterface *> (solver); if (clpSolver) { ClpSimplex * clpSimplex = clpSolver->getModelPtr(); int oneSolveIts = clpSimplex->maximumIterations(); oneSolveIts = CoinMin(1000+2*(clpSimplex->numberRows()+clpSimplex->numberColumns()),oneSolveIts); clpSimplex->setMaximumIterations(oneSolveIts); if (!nodes) { // say give up easily clpSimplex->setMoreSpecialOptions(clpSimplex->moreSpecialOptions() | 64); } else { // get ray int specialOptions = clpSimplex->specialOptions(); specialOptions &= ~0x3100000; specialOptions |= 32; clpSimplex->setSpecialOptions(specialOptions); clpSolver->setSpecialOptions(clpSolver->specialOptions() | 1048576); if ((model_->moreSpecialOptions()&16777216)!=0) { // cutoff is constraint clpSolver->setDblParam(OsiDualObjectiveLimit, COIN_DBL_MAX); } } } # endif const double * lower = solver->getColLower(); const double * upper = solver->getColUpper(); const double * rowLower = solver->getRowLower(); const double * rowUpper = solver->getRowUpper(); const double * solution = solver->getColSolution(); const double * objective = solver->getObjCoefficients(); double integerTolerance = model_->getDblParam(CbcModel::CbcIntegerTolerance); double primalTolerance; solver->getDblParam(OsiPrimalTolerance, primalTolerance); int numberRows = matrix_.getNumRows(); assert (numberRows <= solver->getNumRows()); int numberIntegers = model_->numberIntegers(); const int * integerVariable = model_->integerVariable(); double direction = solver->getObjSense(); // 1 for min, -1 for max double newSolutionValue = direction * solver->getObjValue(); int returnCode = 0; // Column copy const double * element = matrix_.getElements(); const int * row = matrix_.getIndices(); const CoinBigIndex * columnStart = matrix_.getVectorStarts(); const int * columnLength = matrix_.getVectorLengths(); #ifdef DIVE_FIX_BINARY_VARIABLES // Row copy const double * elementByRow = matrixByRow_.getElements(); const int * column = matrixByRow_.getIndices(); const CoinBigIndex * rowStart = matrixByRow_.getVectorStarts(); const int * rowLength = matrixByRow_.getVectorLengths(); #endif // Get solution array for heuristic solution int numberColumns = solver->getNumCols(); memcpy(newSolution, solution, numberColumns*sizeof(double)); // vectors to store the latest variables fixed at their bounds int* columnFixed = new int [numberIntegers]; double* originalBound = new double [numberIntegers+2*numberColumns]; double * lowerBefore = originalBound+numberIntegers; double * upperBefore = lowerBefore+numberColumns; memcpy(lowerBefore,lower,numberColumns*sizeof(double)); memcpy(upperBefore,upper,numberColumns*sizeof(double)); double * lastDjs=newSolution+numberColumns; bool * fixedAtLowerBound = new bool [numberIntegers]; PseudoReducedCost * candidate = new PseudoReducedCost [numberIntegers]; double * random = new double [numberIntegers]; int maxNumberAtBoundToFix = static_cast<int> (floor(percentageToFix_ * numberIntegers)); assert (!maxNumberAtBoundToFix||!nodes); // count how many fractional variables int numberFractionalVariables = 0; for (int i = 0; i < numberIntegers; i++) { random[i] = randomNumberGenerator_.randomDouble() + 0.3; int iColumn = integerVariable[i]; double value = newSolution[iColumn]; if (fabs(floor(value + 0.5) - value) > integerTolerance) { numberFractionalVariables++; } } const double* reducedCost = NULL; // See if not NLP if (model_->solverCharacteristics()->reducedCostsAccurate()) reducedCost = solver->getReducedCost(); int iteration = 0; while (numberFractionalVariables) { iteration++; // initialize any data initializeData(); // select a fractional variable to bound int bestColumn = -1; int bestRound; // -1 rounds down, +1 rounds up bool canRound = selectVariableToBranch(solver, newSolution, bestColumn, bestRound); // if the solution is not trivially roundable, we don't try to round; // if the solution is trivially roundable, we try to round. However, // if the rounded solution is worse than the current incumbent, // then we don't round and proceed normally. In this case, the // bestColumn will be a trivially roundable variable if (canRound) { // check if by rounding all fractional variables // we get a solution with an objective value // better than the current best integer solution double delta = 0.0; for (int i = 0; i < numberIntegers; i++) { int iColumn = integerVariable[i]; double value = newSolution[iColumn]; if (fabs(floor(value + 0.5) - value) > integerTolerance) { assert(downLocks_[i] == 0 || upLocks_[i] == 0); double obj = objective[iColumn]; if (downLocks_[i] == 0 && upLocks_[i] == 0) { if (direction * obj >= 0.0) delta += (floor(value) - value) * obj; else delta += (ceil(value) - value) * obj; } else if (downLocks_[i] == 0) delta += (floor(value) - value) * obj; else delta += (ceil(value) - value) * obj; } } if (direction*(solver->getObjValue() + delta) < solutionValue) { #ifdef DIVE_DEBUG nRoundFeasible++; #endif if (!nodes||bestColumn<0) { // Round all the fractional variables for (int i = 0; i < numberIntegers; i++) { int iColumn = integerVariable[i]; double value = newSolution[iColumn]; if (fabs(floor(value + 0.5) - value) > integerTolerance) { assert(downLocks_[i] == 0 || upLocks_[i] == 0); if (downLocks_[i] == 0 && upLocks_[i] == 0) { if (direction * objective[iColumn] >= 0.0) newSolution[iColumn] = floor(value); else newSolution[iColumn] = ceil(value); } else if (downLocks_[i] == 0) newSolution[iColumn] = floor(value); else newSolution[iColumn] = ceil(value); } } break; } else { // can't round if going to use in branching int i; for (i = 0; i < numberIntegers; i++) { int iColumn = integerVariable[i]; double value = newSolution[bestColumn]; if (fabs(floor(value + 0.5) - value) > integerTolerance) { if (iColumn==bestColumn) { assert(downLocks_[i] == 0 || upLocks_[i] == 0); double obj = objective[bestColumn]; if (downLocks_[i] == 0 && upLocks_[i] == 0) { if (direction * obj >= 0.0) bestRound=-1; else bestRound=1; } else if (downLocks_[i] == 0) bestRound=-1; else bestRound=1; break; } } } } } #ifdef DIVE_DEBUG else nRoundInfeasible++; #endif } // do reduced cost fixing #ifdef DIVE_DEBUG int numberFixed = reducedCostFix(solver); std::cout << "numberReducedCostFixed = " << numberFixed << std::endl; #else reducedCostFix(solver); #endif int numberAtBoundFixed = 0; #ifdef DIVE_FIX_BINARY_VARIABLES // fix binary variables based on pseudo reduced cost if (binVarIndex_.size()) { int cnt = 0; int n = static_cast<int>(binVarIndex_.size()); for (int j = 0; j < n; j++) { int iColumn1 = binVarIndex_[j]; double value = newSolution[iColumn1]; if (fabs(value) <= integerTolerance && lower[iColumn1] != upper[iColumn1]) { double maxPseudoReducedCost = 0.0; #ifdef DIVE_DEBUG std::cout << "iColumn1 = " << iColumn1 << ", value = " << value << std::endl; #endif int iRow = vbRowIndex_[j]; double chosenValue = 0.0; for (int k = rowStart[iRow]; k < rowStart[iRow] + rowLength[iRow]; k++) { int iColumn2 = column[k]; #ifdef DIVE_DEBUG std::cout << "iColumn2 = " << iColumn2 << std::endl; #endif if (iColumn1 != iColumn2) { double pseudoReducedCost = fabs(reducedCost[iColumn2] * elementByRow[k]); #ifdef DIVE_DEBUG int k2; for (k2 = rowStart[iRow]; k2 < rowStart[iRow] + rowLength[iRow]; k2++) { if (column[k2] == iColumn1) break; } std::cout << "reducedCost[" << iColumn2 << "] = " << reducedCost[iColumn2] << ", elementByRow[" << iColumn2 << "] = " << elementByRow[k] << ", elementByRow[" << iColumn1 << "] = " << elementByRow[k2] << ", pseudoRedCost = " << pseudoReducedCost << std::endl; #endif if (pseudoReducedCost > maxPseudoReducedCost) maxPseudoReducedCost = pseudoReducedCost; } else { // save value chosenValue = fabs(elementByRow[k]); } } assert (chosenValue); maxPseudoReducedCost /= chosenValue; #ifdef DIVE_DEBUG std::cout << ", maxPseudoRedCost = " << maxPseudoReducedCost << std::endl; #endif candidate[cnt].var = iColumn1; candidate[cnt++].pseudoRedCost = maxPseudoReducedCost; } } #ifdef DIVE_DEBUG std::cout << "candidates for rounding = " << cnt << std::endl; #endif std::sort(candidate, candidate + cnt, compareBinaryVars); for (int i = 0; i < cnt; i++) { int iColumn = candidate[i].var; if (numberAtBoundFixed < maxNumberAtBoundToFix) { columnFixed[numberAtBoundFixed] = iColumn; originalBound[numberAtBoundFixed] = upper[iColumn]; fixedAtLowerBound[numberAtBoundFixed] = true; solver->setColUpper(iColumn, lower[iColumn]); numberAtBoundFixed++; if (numberAtBoundFixed == maxNumberAtBoundToFix) break; } } } #endif // fix other integer variables that are at their bounds int cnt = 0; #ifdef GAP double gap = 1.0e30; #endif if (reducedCost && true) { #ifndef JJF_ONE cnt = fixOtherVariables(solver, solution, candidate, random); #else #ifdef GAP double cutoff = model_->getCutoff() ; if (cutoff < 1.0e20 && false) { double direction = solver->getObjSense() ; gap = cutoff - solver->getObjValue() * direction ; gap *= 0.1; // Fix more if plausible double tolerance; solver->getDblParam(OsiDualTolerance, tolerance) ; if (gap <= 0.0) gap = tolerance; gap += 100.0 * tolerance; } int nOverGap = 0; #endif int numberFree = 0; int numberFixed = 0; for (int i = 0; i < numberIntegers; i++) { int iColumn = integerVariable[i]; if (upper[iColumn] > lower[iColumn]) { numberFree++; double value = newSolution[iColumn]; if (fabs(floor(value + 0.5) - value) <= integerTolerance) { candidate[cnt].var = iColumn; candidate[cnt++].pseudoRedCost = fabs(reducedCost[iColumn] * random[i]); #ifdef GAP if (fabs(reducedCost[iColumn]) > gap) nOverGap++; #endif } } else { numberFixed++; } } #ifdef GAP int nLeft = maxNumberAtBoundToFix - numberAtBoundFixed; #ifdef CLP_INVESTIGATE4 printf("cutoff %g obj %g nover %d - %d free, %d fixed\n", cutoff, solver->getObjValue(), nOverGap, numberFree, numberFixed); #endif if (nOverGap > nLeft && true) { nOverGap = CoinMin(nOverGap, nLeft + maxNumberAtBoundToFix / 2); maxNumberAtBoundToFix += nOverGap - nLeft; } #else #ifdef CLP_INVESTIGATE4 printf("cutoff %g obj %g - %d free, %d fixed\n", model_->getCutoff(), solver->getObjValue(), numberFree, numberFixed); #endif #endif #endif } else { for (int i = 0; i < numberIntegers; i++) { int iColumn = integerVariable[i]; if (upper[iColumn] > lower[iColumn]) { double value = newSolution[iColumn]; if (fabs(floor(value + 0.5) - value) <= integerTolerance) { candidate[cnt].var = iColumn; candidate[cnt++].pseudoRedCost = numberIntegers - i; } } } } std::sort(candidate, candidate + cnt, compareBinaryVars); for (int i = 0; i < cnt; i++) { int iColumn = candidate[i].var; if (upper[iColumn] > lower[iColumn]) { double value = newSolution[iColumn]; if (fabs(floor(value + 0.5) - value) <= integerTolerance && numberAtBoundFixed < maxNumberAtBoundToFix) { // fix the variable at one of its bounds if (fabs(lower[iColumn] - value) <= integerTolerance) { columnFixed[numberAtBoundFixed] = iColumn; originalBound[numberAtBoundFixed] = upper[iColumn]; fixedAtLowerBound[numberAtBoundFixed] = true; solver->setColUpper(iColumn, lower[iColumn]); numberAtBoundFixed++; } else if (fabs(upper[iColumn] - value) <= integerTolerance) { columnFixed[numberAtBoundFixed] = iColumn; originalBound[numberAtBoundFixed] = lower[iColumn]; fixedAtLowerBound[numberAtBoundFixed] = false; solver->setColLower(iColumn, upper[iColumn]); numberAtBoundFixed++; } if (numberAtBoundFixed == maxNumberAtBoundToFix) break; } } } #ifdef DIVE_DEBUG std::cout << "numberAtBoundFixed = " << numberAtBoundFixed << std::endl; #endif double originalBoundBestColumn; double bestColumnValue; int whichWay; if (bestColumn >= 0) { bestColumnValue = newSolution[bestColumn]; if (bestRound < 0) { originalBoundBestColumn = upper[bestColumn]; solver->setColUpper(bestColumn, floor(bestColumnValue)); whichWay=0; } else { originalBoundBestColumn = lower[bestColumn]; solver->setColLower(bestColumn, ceil(bestColumnValue)); whichWay=1; } } else { break; } int originalBestRound = bestRound; int saveModelOptions = model_->specialOptions(); while (1) { model_->setSpecialOptions(saveModelOptions | 2048); solver->resolve(); model_->setSpecialOptions(saveModelOptions); if (!solver->isAbandoned()&&!solver->isIterationLimitReached()) { numberSimplexIterations += solver->getIterationCount(); } else { numberSimplexIterations = maxSimplexIterations + 1; reasonToStop += 100; break; } if (!solver->isProvenOptimal()) { if (nodes) { if (solver->isProvenPrimalInfeasible()) { if (maxSimplexIterationsAtRoot_!=COIN_INT_MAX) { // stop now printf("stopping on first infeasibility\n"); break; } else if (cuts) { // can do conflict cut printf("could do intermediate conflict cut\n"); bool localCut; OsiRowCut * cut = model_->conflictCut(solver,localCut); if (cut) { if (!localCut) { model_->makePartialCut(cut,solver); cuts[numberCuts++]=cut; } else { delete cut; } } } } else { reasonToStop += 10; break; } } if (numberAtBoundFixed > 0) { // Remove the bound fix for variables that were at bounds for (int i = 0; i < numberAtBoundFixed; i++) { int iColFixed = columnFixed[i]; if (fixedAtLowerBound[i]) solver->setColUpper(iColFixed, originalBound[i]); else solver->setColLower(iColFixed, originalBound[i]); } numberAtBoundFixed = 0; } else if (bestRound == originalBestRound) { bestRound *= (-1); whichWay |=2; if (bestRound < 0) { solver->setColLower(bestColumn, originalBoundBestColumn); solver->setColUpper(bestColumn, floor(bestColumnValue)); } else { solver->setColLower(bestColumn, ceil(bestColumnValue)); solver->setColUpper(bestColumn, originalBoundBestColumn); } } else break; } else break; } if (!solver->isProvenOptimal() || direction*solver->getObjValue() >= solutionValue) { reasonToStop += 1; } else if (iteration > maxIterations_) { reasonToStop += 2; } else if (CoinCpuTime() - time1 > maxTime_) { reasonToStop += 3; } else if (numberSimplexIterations > maxSimplexIterations) { reasonToStop += 4; // also switch off #ifdef CLP_INVESTIGATE printf("switching off diving as too many iterations %d, %d allowed\n", numberSimplexIterations, maxSimplexIterations); #endif when_ = 0; } else if (solver->getIterationCount() > 1000 && iteration > 3 && !nodes) { reasonToStop += 5; // also switch off #ifdef CLP_INVESTIGATE printf("switching off diving one iteration took %d iterations (total %d)\n", solver->getIterationCount(), numberSimplexIterations); #endif when_ = 0; } memcpy(newSolution, solution, numberColumns*sizeof(double)); numberFractionalVariables = 0; double sumFractionalVariables=0.0; for (int i = 0; i < numberIntegers; i++) { int iColumn = integerVariable[i]; double value = newSolution[iColumn]; double away = fabs(floor(value + 0.5) - value); if (away > integerTolerance) { numberFractionalVariables++; sumFractionalVariables += away; } } if (nodes) { // save information //branchValues[numberNodes]=bestColumnValue; //statuses[numberNodes]=whichWay+(bestColumn<<2); //bases[numberNodes]=solver->getWarmStart(); ClpSimplex * simplex = clpSolver->getModelPtr(); CbcSubProblem * sub = new CbcSubProblem(clpSolver,lowerBefore,upperBefore, simplex->statusArray(),numberNodes); nodes[numberNodes]=sub; // other stuff sub->branchValue_=bestColumnValue; sub->problemStatus_=whichWay; sub->branchVariable_=bestColumn; sub->objectiveValue_ = simplex->objectiveValue(); sub->sumInfeasibilities_ = sumFractionalVariables; sub->numberInfeasibilities_ = numberFractionalVariables; printf("DiveNode %d column %d way %d bvalue %g obj %g\n", numberNodes,sub->branchVariable_,sub->problemStatus_, sub->branchValue_,sub->objectiveValue_); numberNodes++; if (solver->isProvenOptimal()) { memcpy(lastDjs,solver->getReducedCost(),numberColumns*sizeof(double)); memcpy(lowerBefore,lower,numberColumns*sizeof(double)); memcpy(upperBefore,upper,numberColumns*sizeof(double)); } } if (!numberFractionalVariables||reasonToStop) break; } if (nodes) { printf("Exiting dive for reason %d\n",reasonToStop); if (reasonToStop>1) { printf("problems in diving\n"); int whichWay=nodes[numberNodes-1]->problemStatus_; CbcSubProblem * sub; if ((whichWay&2)==0) { // leave both ways sub = new CbcSubProblem(*nodes[numberNodes-1]); nodes[numberNodes++]=sub; } else { sub = nodes[numberNodes-1]; } if ((whichWay&1)==0) sub->problemStatus_=whichWay|1; else sub->problemStatus_=whichWay&~1; } if (!numberNodes) { // was good at start! - create fake clpSolver->resolve(); ClpSimplex * simplex = clpSolver->getModelPtr(); CbcSubProblem * sub = new CbcSubProblem(clpSolver,lowerBefore,upperBefore, simplex->statusArray(),numberNodes); nodes[numberNodes]=sub; // other stuff sub->branchValue_=0.0; sub->problemStatus_=0; sub->branchVariable_=-1; sub->objectiveValue_ = simplex->objectiveValue(); sub->sumInfeasibilities_ = 0.0; sub->numberInfeasibilities_ = 0; printf("DiveNode %d column %d way %d bvalue %g obj %g\n", numberNodes,sub->branchVariable_,sub->problemStatus_, sub->branchValue_,sub->objectiveValue_); numberNodes++; assert (solver->isProvenOptimal()); } nodes[numberNodes-1]->problemStatus_ |= 256*reasonToStop; // use djs as well if (solver->isProvenPrimalInfeasible()&&cuts) { // can do conflict cut and re-order printf("could do final conflict cut\n"); bool localCut; OsiRowCut * cut = model_->conflictCut(solver,localCut); if (cut) { printf("cut - need to use conflict and previous djs\n"); if (!localCut) { model_->makePartialCut(cut,solver); cuts[numberCuts++]=cut; } else { delete cut; } } else { printf("bad conflict - just use previous djs\n"); } } } // re-compute new solution value double objOffset = 0.0; solver->getDblParam(OsiObjOffset, objOffset); newSolutionValue = -objOffset; for (int i = 0 ; i < numberColumns ; i++ ) newSolutionValue += objective[i] * newSolution[i]; newSolutionValue *= direction; //printf("new solution value %g %g\n",newSolutionValue,solutionValue); if (newSolutionValue < solutionValue && !reasonToStop) { double * rowActivity = new double[numberRows]; memset(rowActivity, 0, numberRows*sizeof(double)); // paranoid check memset(rowActivity, 0, numberRows*sizeof(double)); for (int i = 0; i < numberColumns; i++) { int j; double value = newSolution[i]; if (value) { for (j = columnStart[i]; j < columnStart[i] + columnLength[i]; j++) { int iRow = row[j]; rowActivity[iRow] += value * element[j]; } } } // check was approximately feasible bool feasible = true; for (int i = 0; i < numberRows; i++) { if (rowActivity[i] < rowLower[i]) { if (rowActivity[i] < rowLower[i] - 1000.0*primalTolerance) feasible = false; } else if (rowActivity[i] > rowUpper[i]) { if (rowActivity[i] > rowUpper[i] + 1000.0*primalTolerance) feasible = false; } } for (int i = 0; i < numberIntegers; i++) { int iColumn = integerVariable[i]; double value = newSolution[iColumn]; if (fabs(floor(value + 0.5) - value) > integerTolerance) { feasible = false; break; } } if (feasible) { // new solution solutionValue = newSolutionValue; //printf("** Solution of %g found by CbcHeuristicDive\n",newSolutionValue); //if (cuts) //clpSolver->getModelPtr()->writeMps("good8.mps", 2); returnCode = 1; } else { // Can easily happen //printf("Debug CbcHeuristicDive giving bad solution\n"); } delete [] rowActivity; } #ifdef DIVE_DEBUG std::cout << "nRoundInfeasible = " << nRoundInfeasible << ", nRoundFeasible = " << nRoundFeasible << ", returnCode = " << returnCode << ", reasonToStop = " << reasonToStop << ", simplexIts = " << numberSimplexIterations << ", iterations = " << iteration << std::endl; #endif delete [] columnFixed; delete [] originalBound; delete [] fixedAtLowerBound; delete [] candidate; delete [] random; delete [] downArray_; downArray_ = NULL; delete [] upArray_; upArray_ = NULL; delete solver; return returnCode; }
void ModelDiscrete(const char * const name) { // example of direct interfaces for discrete distribution OsiClpSolverInterface *osiClp1 = new OsiClpSolverInterface(); double INF=osiClp1->getInfinity(); /* Model dimensions */ int nels=44; // ncol=27, nrow=9 /* Sparse matrix data...organized by row */ int mrow[]={ 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8 }; int mcol[]={ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11, 12, 13, 14, 15, 16, 0, 12, 17, 18, 1, 5, 9, 13, 19, 20, 2, 6, 14, 21, 22, 3, 7, 10, 15, 23, 24, 4, 8, 11, 16, 25, 26 }; double dels[] = { 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, 1.0, 16.0, 9.0, -1.0, 1.0, 15.0, 10.0, 5.0, 11.0, -1.0, 1.0, 28.0, 14.0, 22.0, -1.0, 1.0, 23.0, 15.0, 7.0, 17.0, -1.0, 1.0, 81.0, 57.0, 29.0, 55.0, -1.0, 1.0 }; /* Objective */ /* Objective */ double dobj[]={ 18.0, 21.0, 18.0, 16.0, 10.0, 15.0, 16.0, 14.0, 9.0, 10.0, 9.0, 6.0, 17.0, 16.0, 17.0, 15.0, 10.0, 0.0, 13.0, 0.0, 13.0, 0.0, 7.0, 0.0, 7.0, 0.0, 1.0 }; /* Column bounds */ double dclo[]={ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; double dcup[]={ INF, INF, INF, INF, INF, INF, INF, INF, INF, INF, INF, INF, INF, INF, INF, INF, INF, INF, INF, INF, INF, INF, INF, INF, INF, INF, INF }; /* Row bounds */ double drlo[]={ -INF, -INF, -INF, -INF, 0.0, 4.0, 0.0, 8.0, 10.0 }; double drup[]={ 10.0, 19.0, 25.0, 15.0, 0.0, 7.0, 0.0, 8.0, 90.0 }; /* Stages */ int nstg=2; int n_first_stg_rows=4; int rstg[]={ 0,0,0,0,1,1,1,1,1 }; int cstg[]={ 0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,1, 1,1,1,1,1,1,1,1,1 }; /* Stochastic data */ int nindp=5; int nsamp[]={ 5, 2, 5, 5, 3 }; double demand[]={ 200, 220, 250, 270, 300, 50, 150, 140, 160, 180, 200, 220, 10, 50, 80, 100, 340, 580, 600, 620 }; double dprobs[]={ 0.2, 0.05, 0.35, 0.2, 0.2, 0.3, 0.7, 0.1, 0.2, 0.4, 0.2, 0.1, 0.2, 0.2, 0.3, 0.2, 0.1, 0.1, 0.8, 0.1 }; /* local variables */ int ii,jj; // initialize SmiModel SmiScnModel *smiModel = new SmiScnModel(); smiModel->setOsiSolverHandle(*osiClp1); // set core model using Osi interface OsiClpSolverInterface ocsi; ocsi.loadProblem(CoinPackedMatrix( 1,mrow,mcol,dels,nels),dclo,dcup,dobj,drlo,drup); // core model SmiCoreData *smiCore = new SmiCoreData(&ocsi,nstg,cstg,rstg); cout << "ModelDiscrete: generated Core data" << endl; // Create discrete distribution SmiDiscreteDistribution *smiDD = new SmiDiscreteDistribution(smiCore); cout << "ModelDiscrete: adding random variables" << endl; int index=0; for (jj=0;jj<nindp;jj++) { SmiDiscreteRV *smiRV = new SmiDiscreteRV(1); for (ii=0;ii<nsamp[jj];ii++) { CoinPackedVector empty_vec; CoinPackedMatrix empty_mat; CoinPackedVector cpv_rlo ; CoinPackedVector cpv_rup ; cpv_rlo.insert(n_first_stg_rows + jj, demand[index+ii]); cpv_rup.insert(n_first_stg_rows + jj, demand[index+ii]); smiRV->addEvent(empty_mat,empty_vec,empty_vec,empty_vec,cpv_rlo,cpv_rup,dprobs[index+ii]); cpv_rlo.clear(); cpv_rup.clear(); } smiDD->addDiscreteRV(smiRV); index+=nsamp[jj]; } assert(smiDD->getNumRV() == nindp); cout << "ModelDiscrete: added " << nindp << " random variables" << endl; cout << "ModelDiscrete: processing into scenarios" << endl; smiModel->processDiscreteDistributionIntoScenarios(smiDD); // load problem data into OsiSolver smiModel->loadOsiSolverData(); // get Osi pointer OsiSolverInterface *smiOsi = smiModel->getOsiSolverInterface(); // set some parameters smiOsi->setHintParam(OsiDoPresolveInInitial,true); smiOsi->setHintParam(OsiDoScale,true); smiOsi->setHintParam(OsiDoCrash,true); // solve using Osi Solver smiOsi->initialSolve(); // test optimal value assert(fabs(smiOsi->getObjValue()-1566.042)<0.01); // test solutions const double *dsoln = smiOsi->getColSolution(); double objSum = 0.0; /* The canonical way to traverse the tree: For each scenario, get the leaf node. Then get the parent. Repeat until parent is NULL. (Only the root node has a NULL parent.) */ for(int is=0; is<smiModel->getNumScenarios(); ++is) { /* this loop calculates the scenario objective value */ double scenSum = 0.0; // start with leaf node SmiScnNode *node = smiModel->getLeafNode(is); // leaf node probability is the scenario probability double scenprob = node->getModelProb(); while (node != NULL) { // getColStart returns the starting index of node in OSI model for(int j=node->getColStart(); j<node->getColStart()+node->getNumCols(); ++j) { // getCoreColIndex returns the corresponding Core index // in the original (user's) ordering scenSum += dobj[node->getCoreColIndex(j)]*dsoln[j]; } // get parent of node node = node->getParent(); } objSum += scenSum*scenprob; } assert(fabs(smiOsi->getObjValue()-objSum) < 0.01); // print results printf("Solved stochastic program %s\n", name); printf("Number of rows: %d\n",smiOsi->getNumRows()); printf("Number of cols: %d\n",smiOsi->getNumCols()); printf("Optimal value: %g\n",smiOsi->getObjValue()); }