/* * It is always the case that one of the variables of a doubleton * will be (implied) free, but neither will necessarily be a singleton. * Since in the case of a doubleton the number of non-zero entries * will never increase, though, it makes sense to always eliminate them. * * The col rep and row rep must be consistent. */ const CoinPresolveAction *doubleton_action::presolve (CoinPresolveMatrix *prob, const CoinPresolveAction *next) { double startTime = 0.0; int startEmptyRows=0; int startEmptyColumns = 0; if (prob->tuning_) { startTime = CoinCpuTime(); startEmptyRows = prob->countEmptyRows(); startEmptyColumns = prob->countEmptyCols(); } double *colels = prob->colels_; int *hrow = prob->hrow_; CoinBigIndex *mcstrt = prob->mcstrt_; int *hincol = prob->hincol_; int ncols = prob->ncols_; double *clo = prob->clo_; double *cup = prob->cup_; double *rowels = prob->rowels_; int *hcol = prob->hcol_; CoinBigIndex *mrstrt = prob->mrstrt_; int *hinrow = prob->hinrow_; int nrows = prob->nrows_; double *rlo = prob->rlo_; double *rup = prob->rup_; presolvehlink *clink = prob->clink_; presolvehlink *rlink = prob->rlink_; const unsigned char *integerType = prob->integerType_; double *cost = prob->cost_; int numberLook = prob->numberRowsToDo_; int iLook; int * look = prob->rowsToDo_; const double ztolzb = prob->ztolzb_; action * actions = new action [nrows]; int nactions = 0; int *zeros = prob->usefulColumnInt_; //new int[ncols]; int nzeros = 0; int *fixed = zeros+ncols; //new int[ncols]; int nfixed = 0; unsigned char *rowstat = prob->rowstat_; double *acts = prob->acts_; double * sol = prob->sol_; bool fixInfeasibility = (prob->presolveOptions_&16384)!=0; # if PRESOLVE_CONSISTENCY presolve_consistent(prob) ; presolve_links_ok(prob) ; # endif // wasfor (int irow=0; irow<nrows; irow++) for (iLook=0;iLook<numberLook;iLook++) { int irow = look[iLook]; if (hinrow[irow] == 2 && fabs(rup[irow] - rlo[irow]) <= ZTOLDP) { double rhs = rlo[irow]; CoinBigIndex krs = mrstrt[irow]; int icolx, icoly; CoinBigIndex k; icolx = hcol[krs]; icoly = hcol[krs+1]; if (hincol[icolx]<=0||hincol[icoly]<=0) { // should never happen ? //printf("JJF - doubleton column %d has %d entries and %d has %d\n", // icolx,hincol[icolx],icoly,hincol[icoly]); continue; } // check size if (fabs(rowels[krs]) < ZTOLDP2 || fabs(rowels[krs+1]) < ZTOLDP2) continue; // See if prohibited for any reason if (prob->colProhibited(icolx) || prob->colProhibited(icolx)) continue; // don't bother with fixed variables if (!(fabs(cup[icolx] - clo[icolx]) < ZTOLDP) && !(fabs(cup[icoly] - clo[icoly]) < ZTOLDP)) { double coeffx, coeffy; /* find this row in each of the columns */ CoinBigIndex krowx = presolve_find_row(irow, mcstrt[icolx], mcstrt[icolx] + hincol[icolx], hrow); CoinBigIndex krowy = presolve_find_row(irow, mcstrt[icoly], mcstrt[icoly] + hincol[icoly], hrow); /* Check for integrality: If one variable is integer, keep it and substitute for the continuous variable. If both are integer, substitute only for the forms x = k * y (k integral and non-empty intersection on bounds on x) or x = 1-y, where both x and y are binary. flag bits for integerStatus: 1>>0 x integer 1>>1 y integer */ int integerStatus=0; if (integerType[icolx]) { if (integerType[icoly]) { // both integer int good = 0; double rhs2 = rhs; double value; value=colels[krowx]; if (value<0.0) { value = - value; rhs2 += 1; } if (cup[icolx]==1.0&&clo[icolx]==0.0&&fabs(value-1.0)<1.0e-7) good =1; value=colels[krowy]; if (value<0.0) { value = - value; rhs2 += 1; } if (cup[icoly]==1.0&&clo[icoly]==0.0&&fabs(value-1.0)<1.0e-7) good |= 2; if (good==3&&fabs(rhs2-1.0)<1.0e-7) integerStatus = 3; else integerStatus=-1; if (integerStatus==-1&&!rhs) { // maybe x = k * y; double value1 = colels[krowx]; double value2 = colels[krowy]; double ratio; bool swap=false; if (fabs(value1)>fabs(value2)) { ratio = value1/value2; } else { ratio = value2/value1; swap=true; } ratio=fabs(ratio); if (fabs(ratio-floor(ratio+0.5))<1.0e-12) { // possible integerStatus = swap ? 2 : 1; //printf("poss type %d\n",integerStatus); } } } else { integerStatus = 1; } } else if (integerType[icoly]) { integerStatus = 2; } if (integerStatus<0) { // can still take in some cases bool canDo=false; double value1 = colels[krowx]; double value2 = colels[krowy]; double ratio; bool swap=false; double rhsRatio; if (fabs(value1)>fabs(value2)) { ratio = value1/value2; rhsRatio = rhs/value1; } else { ratio = value2/value1; rhsRatio = rhs/value2; swap=true; } ratio=fabs(ratio); if (fabs(ratio-floor(ratio+0.5))<1.0e-12) { // possible integerStatus = swap ? 2 : 1; // but check rhs if (rhsRatio==floor(rhsRatio+0.5)) canDo=true; } #ifdef COIN_DEVELOP2 if (canDo) printf("Good CoinPresolveDoubleton icolx %d (%g and bounds %g %g) icoly %d (%g and bound %g %g) - rhs %g\n", icolx,colels[krowx],clo[icolx],cup[icolx], icoly,colels[krowy],clo[icoly],cup[icoly],rhs); else printf("Bad CoinPresolveDoubleton icolx %d (%g) icoly %d (%g) - rhs %g\n", icolx,colels[krowx],icoly,colels[krowy],rhs); #endif if (!canDo) continue; } if (integerStatus == 2) { CoinSwap(icoly,icolx); CoinSwap(krowy,krowx); } // HAVE TO JIB WITH ABOVE swapS // if x's coefficient is something like 1000, but y's only something like -1, // then when we postsolve, if x's is close to being out of tolerance, // then y is very likely to be (because y==1000x) . (55) // It it interesting that the number of doubletons found may depend // on which column is substituted away (this is true of baxter.mps). if (!integerStatus) { if (fabs(colels[krowy]) < fabs(colels[krowx])) { CoinSwap(icoly,icolx); CoinSwap(krowy,krowx); } } #if 0 //????? if (integerType[icolx] && clo[icoly] != -PRESOLVE_INF && cup[icoly] != PRESOLVE_INF) { continue; } #endif { CoinBigIndex kcs = mcstrt[icoly]; CoinBigIndex kce = kcs + hincol[icoly]; for (k=kcs; k<kce; k++) { if (hinrow[hrow[k]] == 1) { break; } } // let singleton rows be taken care of first if (k<kce) continue; } coeffx = colels[krowx]; coeffy = colels[krowy]; // it is possible that both x and y are singleton columns // that can cause problems if (hincol[icolx] == 1 && hincol[icoly] == 1) continue; // BE CAUTIOUS and avoid very large relative differences // if this is not done in baxter, then the computed solution isn't optimal, // but gets it in 11995 iterations; the postsolve goes to iteration 16181. // with this, the solution is optimal, but takes 18825 iters; postsolve 18871. #if 0 if (fabs(coeffx) * max_coeff_factor <= fabs(coeffy)) continue; #endif #if 0 if (only_zero_rhs && rhs != 0) continue; if (reject_doubleton(mcstrt, colels, hrow, hincol, -coeffx / coeffy, max_coeff_ratio, irow, icolx, icoly)) continue; #endif // common equations are of the form ax + by = 0, or x + y >= lo { PRESOLVE_DETAIL_PRINT(printf("pre_doubleton %dC %dC %dR E\n", icoly,icolx,irow)); action *s = &actions[nactions]; nactions++; s->row = irow; s->icolx = icolx; s->clox = clo[icolx]; s->cupx = cup[icolx]; s->costx = cost[icolx]; s->icoly = icoly; s->costy = cost[icoly]; s->rlo = rlo[irow]; s->coeffx = coeffx; s->coeffy = coeffy; s->ncolx = hincol[icolx]; s->ncoly = hincol[icoly]; if (s->ncoly<s->ncolx) { // Take out row s->colel = presolve_dupmajor(colels,hrow,hincol[icoly], mcstrt[icoly],irow) ; s->ncolx=0; } else { s->colel = presolve_dupmajor(colels,hrow,hincol[icolx], mcstrt[icolx],irow) ; s->ncoly=0; } } /* * This moves the bounds information for y onto x, * making y free and allowing us to substitute it away. * * a x + b y = c * l1 <= x <= u1 * l2 <= y <= u2 ==> * * l2 <= (c - a x) / b <= u2 * b/-a > 0 ==> (b l2 - c) / -a <= x <= (b u2 - c) / -a * b/-a < 0 ==> (b u2 - c) / -a <= x <= (b l2 - c) / -a */ { double lo1 = -PRESOLVE_INF; double up1 = PRESOLVE_INF; //PRESOLVEASSERT((coeffx < 0) == (coeffy/-coeffx < 0)); // (coeffy/-coeffx < 0) == (coeffy<0 == coeffx<0) if (-PRESOLVE_INF < clo[icoly]) { if (coeffx * coeffy < 0) lo1 = (coeffy * clo[icoly] - rhs) / -coeffx; else up1 = (coeffy * clo[icoly] - rhs) / -coeffx; } if (cup[icoly] < PRESOLVE_INF) { if (coeffx * coeffy < 0) up1 = (coeffy * cup[icoly] - rhs) / -coeffx; else lo1 = (coeffy * cup[icoly] - rhs) / -coeffx; } // costy y = costy ((c - a x) / b) = (costy c)/b + x (costy -a)/b // the effect of maxmin cancels out cost[icolx] += cost[icoly] * (-coeffx / coeffy); prob->change_bias(cost[icoly] * rhs / coeffy); if (0 /*integerType[icolx]*/) { abort(); /* no change possible for now */ #if 0 lo1 = trunc(lo1); up1 = trunc(up1); /* trunc(3.5) == 3.0 */ /* trunc(-3.5) == -3.0 */ /* I think this is ok */ if (lo1 > clo[icolx]) { (clo[icolx] <= 0.0) clo[icolx] = ? ilo clo[icolx] = ilo; cup[icolx] = iup; } #endif } else {
bool BlisConGenerator::generateCons(OsiCuts & coinCuts , bool fullScan) { bool status = false; if (strategy_ == -2) { // This con generator has been disabled. return false; } OsiSolverInterface * solver = model_->solver(); #if defined(BLIS_DEBUG_MORE) std::cout << "model_->getNodeCount() = " << model_->getNodeCount() << std::endl; #endif if ( fullScan || ((strategy_ > 0) && (model_->getNumNodes() % strategy_) == 0) ) { //-------------------------------------------------- // Start to generate cons ... //-------------------------------------------------- int j; double start = CoinCpuTime(); int numConsBefore = coinCuts.sizeCuts(); int numRowsBefore = coinCuts.sizeRowCuts(); assert(generator_ != NULL); CglProbing* generator = dynamic_cast<CglProbing *>(generator_); if (!generator) { generator_->generateCuts(*solver, coinCuts); } else { // It is probing - return tight column bound CglTreeInfo info; generator->generateCutsAndModify(*solver, coinCuts, &info); const double * tightLower = generator->tightLower(); const double * lower = solver->getColLower(); const double * tightUpper = generator->tightUpper(); const double * upper = solver->getColUpper(); const double * solution = solver->getColSolution(); int numberColumns = solver->getNumCols(); double primalTolerance = 1.0e-8; for (j = 0; j < numberColumns; ++j) { if ( (tightUpper[j] == tightLower[j]) && (upper[j] > lower[j]) ) { // fix column j solver->setColLower(j, tightLower[j]); solver->setColUpper(j, tightUpper[j]); if ( (tightLower[j] > solution[j] + primalTolerance) || (tightUpper[j] < solution[j] - primalTolerance) ) { status = true; } } } } // EOF probing. //-------------------------------------------------- // Remove zero length row cuts. //-------------------------------------------------- int numRowCons = coinCuts.sizeRowCuts(); for (j = numRowsBefore; j < numRowCons; ++j) { OsiRowCut & rCut = coinCuts.rowCut(j); int len = rCut.row().getNumElements(); #ifdef BLIS_DEBUG_MORE std::cout << "Cut " << j<<": length = " << len << std::endl; #endif if (len == 0) { // Empty cuts coinCuts.eraseRowCut(j); --j; --numRowCons; #ifdef BLIS_DEBUG std::cout << "WARNING: Empty cut from " << name_ << std::endl; #endif } else if (len < 0) { #ifdef BLIS_DEBUG std::cout << "ERROR: Cut length = " << len << std::endl; #endif // Error assert(0); } } //-------------------------------------------------- // Update statistics. //-------------------------------------------------- ++calls_; numConsGenerated_ += (coinCuts.sizeCuts() - numConsBefore); time_ += (CoinCpuTime() - start); if (numConsGenerated_ == 0) { ++noConsCalls_; } } return status; }
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[]) { // Get data std::string fileName = "./sudoku_sample.csv"; if (argc>=2) fileName = argv[1]; FILE * fp = fopen(fileName.c_str(),"r"); if (!fp) { printf("Unable to open file %s\n",fileName.c_str()); exit(0); } #define MAX_SIZE 16 int valueOffset=1; double lo[MAX_SIZE*MAX_SIZE],up[MAX_SIZE*MAX_SIZE]; char line[80]; int row,column; /*************************************** Read .csv file and see if 9 or 16 Su Doku ***************************************/ int size=9; for (row=0;row<size;row++) { fgets(line,80,fp); // Get size of sudoku puzzle (9 or 16) if (!row) { int get=0; size=1; while (line[get]>=32) { if (line[get]==',') size++; get++; } assert (size==9||size==16); printf("Solving Su Doku of size %d\n",size); if (size==16) valueOffset=0; } int get=0; for (column=0;column<size;column++) { lo[size*row+column]=valueOffset; up[size*row+column]=valueOffset-1+size; if (line[get]!=','&&line[get]>=32) { // skip blanks if (line[get]==' ') { get++; continue; } int value = line[get]-'0'; if (size==9) { assert (value>=1&&value<=9); } else { assert (size==16); if (value<0||value>9) { if (line[get]=='"') { get++; value = 10 + line[get]-'A'; if (value<10||value>15) { value = 10 + line[get]-'a'; } get++; } else { value = 10 + line[get]-'A'; if (value<10||value>15) { value = 10 + line[get]-'a'; } } } assert (value>=0&&value<=15); } lo[size*row+column]=value; up[size*row+column]=value; get++; } get++; } } int block_size = (int) sqrt ((double) size); /*************************************** Now build rules for all different 3*9 or 3*16 sets of variables Number variables by row*size+column ***************************************/ int starts[3*MAX_SIZE+1]; int which[3*MAX_SIZE*MAX_SIZE]; int put=0; int set=0; starts[0]=0; // By row for (row=0;row<size;row++) { for (column=0;column<size;column++) which[put++]=row*size+column; starts[set+1]=put; set++; } // By column for (column=0;column<size;column++) { for (row=0;row<size;row++) which[put++]=row*size+column; starts[set+1]=put; set++; } // By box for (row=0;row<size;row+=block_size) { for (column=0;column<size;column+=block_size) { for (int row2=row;row2<row+block_size;row2++) { for (int column2=column;column2<column+block_size;column2++) which[put++]=row2*size+column2; } starts[set+1]=put; set++; } } OsiClpSolverInterface solver1; /*************************************** Create model Set variables to be general integer variables although priorities probably mean that it won't matter ***************************************/ CoinModel build; // Columns char name[4]; for (row=0;row<size;row++) { for (column=0;column<size;column++) { if (row<10) { if (column<10) sprintf(name,"X%d%d",row,column); else sprintf(name,"X%d%c",row,'A'+(column-10)); } else { if (column<10) sprintf(name,"X%c%d",'A'+(row-10),column); else sprintf(name,"X%c%c",'A'+(row-10),'A'+(column-10)); } double value = CoinDrand48()*100.0; build.addColumn(0,NULL,NULL,lo[size*row+column], up[size*row+column], value, name,true); } } /*************************************** Now add in extra variables for N way branching ***************************************/ for (row=0;row<size;row++) { for (column=0;column<size;column++) { int iColumn = size*row+column; double value = lo[iColumn]; if (value<up[iColumn]) { for (int i=0;i<size;i++) build.addColumn(0,NULL,NULL,0.0,1.0,0.0); } else { // fixed // obviously could do better if we missed out variables int which = ((int) value) - valueOffset; for (int i=0;i<size;i++) { if (i!=which) build.addColumn(0,NULL,NULL,0.0,0.0,0.0); else build.addColumn(0,NULL,NULL,0.0,1.0,0.0); } } } } /*************************************** Now rows ***************************************/ double values[]={1.0,1.0,1.0,1.0, 1.0,1.0,1.0,1.0, 1.0,1.0,1.0,1.0, 1.0,1.0,1.0,1.0}; int indices[MAX_SIZE+1]; double rhs = size==9 ? 45.0 : 120.0; for (row=0;row<3*size;row++) { int iStart = starts[row]; for (column=0;column<size;column++) indices[column]=which[column+iStart]; build.addRow(size,indices,values,rhs,rhs); } double values2[MAX_SIZE+1]; values2[0]=-1.0; for (row=0;row<size;row++) values2[row+1]=row+valueOffset; // Now add rows for extra variables for (row=0;row<size;row++) { for (column=0;column<size;column++) { int iColumn = row*size+column; int base = size*size + iColumn*size; indices[0]=iColumn; for (int i=0;i<size;i++) indices[i+1]=base+i; build.addRow(size+1,indices,values2,0.0,0.0); } } solver1.loadFromCoinModel(build); build.writeMps("xx.mps"); double time1 = CoinCpuTime(); solver1.initialSolve(); CbcModel model(solver1); model.solver()->setHintParam(OsiDoReducePrint,true,OsiHintTry); model.solver()->setHintParam(OsiDoScale,false,OsiHintTry); /*************************************** Add in All different cut generator and All different branching So we will have integers then cut branching then N way branching in reverse priority order ***************************************/ // Cut generator CglAllDifferent allDifferent(3*size,starts,which); model.addCutGenerator(&allDifferent,-99,"allDifferent"); model.cutGenerator(0)->setWhatDepth(5); CbcObject ** objects = new CbcObject * [4*size*size]; int nObj=0; for (row=0;row<3*size;row++) { int iStart = starts[row]; objects[row]= new CbcBranchAllDifferent(&model,size,which+iStart); objects[row]->setPriority(2000+nObj); // do after rest satisfied nObj++; } /*************************************** Add in N way branching and while we are at it add in cuts ***************************************/ CglStored stored; for (row=0;row<size;row++) { for (column=0;column<size;column++) { int iColumn = row*size+column; int base = size*size + iColumn*size; int i; for ( i=0;i<size;i++) indices[i]=base+i; CbcNWay * obj = new CbcNWay(&model,size,indices,nObj); int seq[200]; int newUpper[200]; memset(newUpper,0,sizeof(newUpper)); for (i=0;i<size;i++) { int state=9999; int one=1; int nFix=1; // Fix real variable seq[0]=iColumn; newUpper[0]=valueOffset+i; int kColumn = base+i; int j; // same row for (j=0;j<size;j++) { int jColumn = row*size+j; int jjColumn = size*size+jColumn*size+i; if (jjColumn!=kColumn) { seq[nFix++]=jjColumn; // must be zero } } // same column for (j=0;j<size;j++) { int jColumn = j*size+column; int jjColumn = size*size+jColumn*size+i; if (jjColumn!=kColumn) { seq[nFix++]=jjColumn; // must be zero } } // same block int kRow = row/block_size; kRow *= block_size; int kCol = column/block_size; kCol *= block_size; for (j=kRow;j<kRow+block_size;j++) { for (int jc=kCol;jc<kCol+block_size;jc++) { int jColumn = j*size+jc; int jjColumn = size*size+jColumn*size+i; if (jjColumn!=kColumn) { seq[nFix++]=jjColumn; // must be zero } } } // seem to need following? const int * upperAddress = newUpper; const int * seqAddress = seq; CbcFixVariable fix(1,&state,&one,&upperAddress,&seqAddress,&nFix,&upperAddress,&seqAddress); obj->setConsequence(indices[i],fix); // Now do as cuts for (int kk=1;kk<nFix;kk++) { int jColumn = seq[kk]; int cutInd[2]; cutInd[0]=kColumn; if (jColumn>kColumn) { cutInd[1]=jColumn; stored.addCut(-COIN_DBL_MAX,1.0,2,cutInd,values); } } } objects[nObj]= obj; objects[nObj]->setPriority(nObj); nObj++; } } model.addObjects(nObj,objects); for (row=0;row<nObj;row++) delete objects[row]; delete [] objects; model.messageHandler()->setLogLevel(1); model.addCutGenerator(&stored,1,"stored"); // Say we want timings int numberGenerators = model.numberCutGenerators(); int iGenerator; for (iGenerator=0;iGenerator<numberGenerators;iGenerator++) { CbcCutGenerator * generator = model.cutGenerator(iGenerator); generator->setTiming(true); } // Set this to get all solutions (all ones in newspapers should only have one) //model.setCutoffIncrement(-1.0e6); /*************************************** Do branch and bound ***************************************/ // Do complete search model.branchAndBound(); std::cout<<"took "<<CoinCpuTime()-time1<<" seconds, " <<model.getNodeCount()<<" nodes with objective " <<model.getObjValue() <<(!model.status() ? " Finished" : " Not finished") <<std::endl; /*************************************** Print solution and check it is feasible We could modify output so could be imported by spreadsheet ***************************************/ if (model.getMinimizationObjValue()<1.0e50) { const double * solution = model.bestSolution(); int put=0; for (row=0;row<size;row++) { for (column=0;column<size;column++) { int value = (int) floor(solution[row*size+column]+0.5); assert (value>=lo[put]&&value<=up[put]); // save for later test lo[put++]=value; printf("%d ",value); } printf("\n"); } // check valid bool valid=true; // By row for (row=0;row<size;row++) { put=0; for (column=0;column<size;column++) which[put++]=row*size+column; assert (put==size); int i; for (i=0;i<put;i++) which[i]=(int) lo[which[i]]; std::sort(which,which+put); int last = valueOffset-1; for (i=0;i<put;i++) { int value=which[i]; if (value!=last+1) valid=false; last=value; } } // By column for (column=0;column<size;column++) { put=0; for (row=0;row<size;row++) which[put++]=row*size+column; assert (put==size); int i; for (i=0;i<put;i++) which[i]=(int) lo[which[i]]; std::sort(which,which+put); int last = valueOffset-1; for (i=0;i<put;i++) { int value=which[i]; if (value!=last+1) valid=false; last=value; } } // By box for (row=0;row<size;row+=block_size) { for (column=0;column<size;column+=block_size) { put=0; for (int row2=row;row2<row+block_size;row2++) { for (int column2=column;column2<column+block_size;column2++) which[put++]=row2*size+column2; } assert (put==size); int i; for (i=0;i<put;i++) which[i]=(int) lo[which[i]]; std::sort(which,which+put); int last = valueOffset-1; for (i=0;i<put;i++) { int value=which[i]; if (value!=last+1) valid=false; last=value; } } } if (valid) { printf("solution is valid\n"); } else { printf("solution is not valid\n"); abort(); } } return 0; }
// ** Temporary version int ClpPdco::pdco( ClpPdcoBase * stuff, Options &options, Info &info, Outfo &outfo) { // D1, D2 are positive-definite diagonal matrices defined from d1, d2. // In particular, d2 indicates the accuracy required for // satisfying each row of Ax = b. // // D1 and D2 (via d1 and d2) provide primal and dual regularization // respectively. They ensure that the primal and dual solutions // (x,r) and (y,z) are unique and bounded. // // A scalar d1 is equivalent to d1 = ones(n,1), D1 = diag(d1). // A scalar d2 is equivalent to d2 = ones(m,1), D2 = diag(d2). // Typically, d1 = d2 = 1e-4. // These values perturb phi(x) only slightly (by about 1e-8) and request // that A*x = b be satisfied quite accurately (to about 1e-8). // Set d1 = 1e-4, d2 = 1 for least-squares problems with bound constraints. // The problem is then // // minimize phi(x) + 1/2 norm(d1*x)^2 + 1/2 norm(A*x - b)^2 // subject to bl <= x <= bu. // // More generally, d1 and d2 may be n and m vectors containing any positive // values (preferably not too small, and typically no larger than 1). // Bigger elements of d1 and d2 improve the stability of the solver. // // At an optimal solution, if x(j) is on its lower or upper bound, // the corresponding z(j) is positive or negative respectively. // If x(j) is between its bounds, z(j) = 0. // If bl(j) = bu(j), x(j) is fixed at that value and z(j) may have // either sign. // // Also, r and y satisfy r = D2 y, so that Ax + D2^2 y = b. // Thus if d2(i) = 1e-4, the i-th row of Ax = b will be satisfied to // approximately 1e-8. This determines how large d2(i) can safely be. // // // EXTERNAL FUNCTIONS: // options = pdcoSet; provided with pdco.m // [obj,grad,hess] = pdObj( x ); provided by user // y = pdMat( name,mode,m,n,x ); provided by user if pdMat // is a string, not a matrix // // INPUT ARGUMENTS: // pdObj is a string containing the name of a function pdObj.m // or a function_handle for such a function // such that [obj,grad,hess] = pdObj(x) defines // obj = phi(x) : a scalar, // grad = gradient of phi(x) : an n-vector, // hess = diag(Hessian of phi): an n-vector. // Examples: // If phi(x) is the linear function c"x, pdObj should return // [obj,grad,hess] = [c"*x, c, zeros(n,1)]. // If phi(x) is the entropy function E(x) = sum x(j) log x(j), // [obj,grad,hess] = [E(x), log(x)+1, 1./x]. // pdMat may be an ifexplicit m x n matrix A (preferably sparse!), // or a string containing the name of a function pdMat.m // or a function_handle for such a function // such that y = pdMat( name,mode,m,n,x ) // returns y = A*x (mode=1) or y = A"*x (mode=2). // The input parameter "name" will be the string pdMat. // b is an m-vector. // bl is an n-vector of lower bounds. Non-existent bounds // may be represented by bl(j) = -Inf or bl(j) <= -1e+20. // bu is an n-vector of upper bounds. Non-existent bounds // may be represented by bu(j) = Inf or bu(j) >= 1e+20. // d1, d2 may be positive scalars or positive vectors (see above). // options is a structure that may be set and altered by pdcoSet // (type help pdcoSet). // x0, y0, z0 provide an initial solution. // xsize, zsize are estimates of the biggest x and z at the solution. // They are used to scale (x,y,z). Good estimates // should improve the performance of the barrier method. // // // OUTPUT ARGUMENTS: // x is the primal solution. // y is the dual solution associated with Ax + D2 r = b. // z is the dual solution associated with bl <= x <= bu. // inform = 0 if a solution is found; // = 1 if too many iterations were required; // = 2 if the linesearch failed too often. // PDitns is the number of Primal-Dual Barrier iterations required. // CGitns is the number of Conjugate-Gradient iterations required // if an iterative solver is used (LSQR). // time is the cpu time used. //---------------------------------------------------------------------- // PRIVATE FUNCTIONS: // pdxxxbounds // pdxxxdistrib // pdxxxlsqr // pdxxxlsqrmat // pdxxxmat // pdxxxmerit // pdxxxresid1 // pdxxxresid2 // pdxxxstep // // GLOBAL VARIABLES: // global pdDDD1 pdDDD2 pdDDD3 // // // NOTES: // The matrix A should be reasonably well scaled: norm(A,inf) =~ 1. // The vector b and objective phi(x) may be of any size, but ensure that // xsize and zsize are reasonably close to norm(x,inf) and norm(z,inf) // at the solution. // // The files defining pdObj and pdMat // must not be called Fname.m or Aname.m!! // // // AUTHOR: // Michael Saunders, Systems Optimization Laboratory (SOL), // Stanford University, Stanford, California, USA. // [email protected] // // CONTRIBUTORS: // Byunggyoo Kim, SOL, Stanford University. // [email protected] // // DEVELOPMENT: // 20 Jun 1997: Original version of pdsco.m derived from pdlp0.m. // 29 Sep 2002: Original version of pdco.m derived from pdsco.m. // Introduced D1, D2 in place of gamma*I, delta*I // and allowed for general bounds bl <= x <= bu. // 06 Oct 2002: Allowed for fixed variabes: bl(j) = bu(j) for any j. // 15 Oct 2002: Eliminated some work vectors (since m, n might be LARGE). // Modularized residuals, linesearch // 16 Oct 2002: pdxxx..., pdDDD... names rationalized. // pdAAA eliminated (global copy of A). // Aname is now used directly as an ifexplicit A or a function. // NOTE: If Aname is a function, it now has an extra parameter. // 23 Oct 2002: Fname and Aname can now be function handles. // 01 Nov 2002: Bug fixed in feval in pdxxxmat. //----------------------------------------------------------------------- // global pdDDD1 pdDDD2 pdDDD3 double inf = 1.0e30; double eps = 1.0e-15; double atolold = -1.0, r3ratio = -1.0, Pinf, Dinf, Cinf, Cinf0; printf("\n --------------------------------------------------------"); printf("\n pdco.m Version of 01 Nov 2002"); printf("\n Primal-dual barrier method to minimize a convex function"); printf("\n subject to linear constraints Ax + r = b, bl <= x <= bu"); printf("\n --------------------------------------------------------\n"); int m = numberRows_; int n = numberColumns_; bool ifexplicit = true; CoinDenseVector<double> b(m, rhs_); CoinDenseVector<double> x(n, x_); CoinDenseVector<double> y(m, y_); CoinDenseVector<double> z(n, dj_); //delete old arrays delete [] rhs_; delete [] x_; delete [] y_; delete [] dj_; rhs_ = NULL; x_ = NULL; y_ = NULL; dj_ = NULL; // Save stuff so available elsewhere pdcoStuff_ = stuff; double normb = b.infNorm(); double normx0 = x.infNorm(); double normy0 = y.infNorm(); double normz0 = z.infNorm(); printf("\nmax |b | = %8g max |x0| = %8g", normb , normx0); printf( " xsize = %8g", xsize_); printf("\nmax |y0| = %8g max |z0| = %8g", normy0, normz0); printf( " zsize = %8g", zsize_); //--------------------------------------------------------------------- // Initialize. //--------------------------------------------------------------------- //true = 1; //false = 0; //zn = zeros(n,1); //int nb = n + m; int CGitns = 0; int inform = 0; //--------------------------------------------------------------------- // Only allow scalar d1, d2 for now //--------------------------------------------------------------------- /* if (d1_->size()==1) d1_->resize(n, d1_->getElements()[0]); // Allow scalar d1, d2 if (d2_->size()==1) d2->resize(m, d2->getElements()[0]); // to mean dk * unit vector */ assert (stuff->sizeD1() == 1); double d1 = stuff->getD1(); double d2 = stuff->getD2(); //--------------------------------------------------------------------- // Grab input options. //--------------------------------------------------------------------- int maxitn = options.MaxIter; double featol = options.FeaTol; double opttol = options.OptTol; double steptol = options.StepTol; int stepSame = 1; /* options.StepSame; // 1 means stepx == stepz */ double x0min = options.x0min; double z0min = options.z0min; double mu0 = options.mu0; int LSproblem = options.LSproblem; // See below int LSmethod = options.LSmethod; // 1=Cholesky 2=QR 3=LSQR int itnlim = options.LSQRMaxIter * CoinMin(m, n); double atol1 = options.LSQRatol1; // Initial atol double atol2 = options.LSQRatol2; // Smallest atol,unless atol1 is smaller double conlim = options.LSQRconlim; //int wait = options.wait; // LSproblem: // 1 = dy 2 = dy shifted, DLS // 11 = s 12 = s shifted, DLS (dx = Ds) // 21 = dx // 31 = 3x3 system, symmetrized by Z^{1/2} // 32 = 2x2 system, symmetrized by X^{1/2} //--------------------------------------------------------------------- // Set other parameters. //--------------------------------------------------------------------- int kminor = 0; // 1 stops after each iteration double eta = 1e-4; // Linesearch tolerance for "sufficient descent" double maxf = 10; // Linesearch backtrack limit (function evaluations) double maxfail = 1; // Linesearch failure limit (consecutive iterations) double bigcenter = 1e+3; // mu is reduced if center < bigcenter. // Parameters for LSQR. double atolmin = eps; // Smallest atol if linesearch back-tracks double btol = 0; // Should be small (zero is ok) double show = false; // Controls lsqr iteration log /* double gamma = d1->infNorm(); double delta = d2->infNorm(); */ double gamma = d1; double delta = d2; printf("\n\nx0min = %8g featol = %8.1e", x0min, featol); printf( " d1max = %8.1e", gamma); printf( "\nz0min = %8g opttol = %8.1e", z0min, opttol); printf( " d2max = %8.1e", delta); printf( "\nmu0 = %8.1e steptol = %8g", mu0 , steptol); printf( " bigcenter= %8g" , bigcenter); printf("\n\nLSQR:"); printf("\natol1 = %8.1e atol2 = %8.1e", atol1 , atol2 ); printf( " btol = %8.1e", btol ); printf("\nconlim = %8.1e itnlim = %8d" , conlim, itnlim); printf( " show = %8g" , show ); // LSmethod = 3; ////// Hardwire LSQR // LSproblem = 1; ////// and LS problem defining "dy". /* if wait printf("\n\nReview parameters... then type "return"\n") keyboard end */ if (eta < 0) printf("\n\nLinesearch disabled by eta < 0"); //--------------------------------------------------------------------- // All parameters have now been set. //--------------------------------------------------------------------- double time = CoinCpuTime(); //bool useChol = (LSmethod == 1); //bool useQR = (LSmethod == 2); bool direct = (LSmethod <= 2 && ifexplicit); char solver[6]; strcpy(solver, " LSQR"); //--------------------------------------------------------------------- // Categorize bounds and allow for fixed variables by modifying b. //--------------------------------------------------------------------- int nlow, nupp, nfix; int *bptrs[3] = {0}; getBoundTypes(&nlow, &nupp, &nfix, bptrs ); int *low = bptrs[0]; int *upp = bptrs[1]; int *fix = bptrs[2]; int nU = n; if (nupp == 0) nU = 1; //Make dummy vectors if no Upper bounds //--------------------------------------------------------------------- // Get pointers to local copy of model bounds //--------------------------------------------------------------------- CoinDenseVector<double> bl(n, columnLower_); double *bl_elts = bl.getElements(); CoinDenseVector<double> bu(nU, columnUpper_); // this is dummy if no UB double *bu_elts = bu.getElements(); CoinDenseVector<double> r1(m, 0.0); double *r1_elts = r1.getElements(); CoinDenseVector<double> x1(n, 0.0); double *x1_elts = x1.getElements(); if (nfix > 0) { for (int k = 0; k < nfix; k++) x1_elts[fix[k]] = bl[fix[k]]; matVecMult(1, r1, x1); b = b - r1; // At some stage, might want to look at normfix = norm(r1,inf); } //--------------------------------------------------------------------- // Scale the input data. // The scaled variables are // xbar = x/beta, // ybar = y/zeta, // zbar = z/zeta. // Define // theta = beta*zeta; // The scaled function is // phibar = ( 1 /theta) fbar(beta*xbar), // gradient = (beta /theta) grad, // Hessian = (beta2/theta) hess. //--------------------------------------------------------------------- double beta = xsize_; if (beta == 0) beta = 1; // beta scales b, x. double zeta = zsize_; if (zeta == 0) zeta = 1; // zeta scales y, z. double theta = beta * zeta; // theta scales obj. // (theta could be anything, but theta = beta*zeta makes // scaled grad = grad/zeta = 1 approximately if zeta is chosen right.) for (int k = 0; k < nlow; k++) bl_elts[low[k]] = bl_elts[low[k]] / beta; for (int k = 0; k < nupp; k++) bu_elts[upp[k]] = bu_elts[upp[k]] / beta; d1 = d1 * ( beta / sqrt(theta) ); d2 = d2 * ( sqrt(theta) / beta ); double beta2 = beta * beta; b.scale( (1.0 / beta) ); y.scale( (1.0 / zeta) ); x.scale( (1.0 / beta) ); z.scale( (1.0 / zeta) ); //--------------------------------------------------------------------- // Initialize vectors that are not fully used if bounds are missing. //--------------------------------------------------------------------- CoinDenseVector<double> rL(n, 0.0); CoinDenseVector<double> cL(n, 0.0); CoinDenseVector<double> z1(n, 0.0); CoinDenseVector<double> dx1(n, 0.0); CoinDenseVector<double> dz1(n, 0.0); CoinDenseVector<double> r2(n, 0.0); // Assign upper bd regions (dummy if no UBs) CoinDenseVector<double> rU(nU, 0.0); CoinDenseVector<double> cU(nU, 0.0); CoinDenseVector<double> x2(nU, 0.0); CoinDenseVector<double> z2(nU, 0.0); CoinDenseVector<double> dx2(nU, 0.0); CoinDenseVector<double> dz2(nU, 0.0); //--------------------------------------------------------------------- // Initialize x, y, z, objective, etc. //--------------------------------------------------------------------- CoinDenseVector<double> dx(n, 0.0); CoinDenseVector<double> dy(m, 0.0); CoinDenseVector<double> Pr(m); CoinDenseVector<double> D(n); double *D_elts = D.getElements(); CoinDenseVector<double> w(n); double *w_elts = w.getElements(); CoinDenseVector<double> rhs(m + n); //--------------------------------------------------------------------- // Pull out the element array pointers for efficiency //--------------------------------------------------------------------- double *x_elts = x.getElements(); double *x2_elts = x2.getElements(); double *z_elts = z.getElements(); double *z1_elts = z1.getElements(); double *z2_elts = z2.getElements(); for (int k = 0; k < nlow; k++) { x_elts[low[k]] = CoinMax( x_elts[low[k]], bl[low[k]]); x1_elts[low[k]] = CoinMax( x_elts[low[k]] - bl[low[k]], x0min ); z1_elts[low[k]] = CoinMax( z_elts[low[k]], z0min ); } for (int k = 0; k < nupp; k++) { x_elts[upp[k]] = CoinMin( x_elts[upp[k]], bu[upp[k]]); x2_elts[upp[k]] = CoinMax(bu[upp[k]] - x_elts[upp[k]], x0min ); z2_elts[upp[k]] = CoinMax(-z_elts[upp[k]], z0min ); } //////////////////// Assume hessian is diagonal. ////////////////////// // [obj,grad,hess] = feval( Fname, (x*beta) ); x.scale(beta); double obj = getObj(x); CoinDenseVector<double> grad(n); getGrad(x, grad); CoinDenseVector<double> H(n); getHessian(x , H); x.scale((1.0 / beta)); //double * g_elts = grad.getElements(); double * H_elts = H.getElements(); obj /= theta; // Scaled obj. grad = grad * (beta / theta) + (d1 * d1) * x; // grad includes x regularization. H = H * (beta2 / theta) + (d1 * d1) ; // H includes x regularization. /*--------------------------------------------------------------------- // Compute primal and dual residuals: // r1 = b - Aprod(x) - d2*d2*y; // r2 = grad - Atprod(y) + z2 - z1; // rL = bl - x + x1; // rU = x + x2 - bu; */ //--------------------------------------------------------------------- // [r1,r2,rL,rU,Pinf,Dinf] = ... // pdxxxresid1( Aname,fix,low,upp, ... // b,bl,bu,d1,d2,grad,rL,rU,x,x1,x2,y,z1,z2 ); pdxxxresid1( this, nlow, nupp, nfix, low, upp, fix, b, bl_elts, bu_elts, d1, d2, grad, rL, rU, x, x1, x2, y, z1, z2, r1, r2, &Pinf, &Dinf); //--------------------------------------------------------------------- // Initialize mu and complementarity residuals: // cL = mu*e - X1*z1. // cU = mu*e - X2*z2. // // 25 Jan 2001: Now that b and obj are scaled (and hence x,y,z), // we should be able to use mufirst = mu0 (absolute value). // 0.1 worked poorly on StarTest1 with x0min = z0min = 0.1. // 29 Jan 2001: We might as well use mu0 = x0min * z0min; // so that most variables are centered after a warm start. // 29 Sep 2002: Use mufirst = mu0*(x0min * z0min), // regarding mu0 as a scaling of the initial center. //--------------------------------------------------------------------- // double mufirst = mu0*(x0min * z0min); double mufirst = mu0; // revert to absolute value double mulast = 0.1 * opttol; mulast = CoinMin( mulast, mufirst ); double mu = mufirst; double center, fmerit; pdxxxresid2( mu, nlow, nupp, low, upp, cL, cU, x1, x2, z1, z2, ¢er, &Cinf, &Cinf0 ); fmerit = pdxxxmerit(nlow, nupp, low, upp, r1, r2, rL, rU, cL, cU ); // Initialize other things. bool precon = true; double PDitns = 0; //bool converged = false; double atol = atol1; atol2 = CoinMax( atol2, atolmin ); atolmin = atol2; // pdDDD2 = d2; // Global vector for diagonal matrix D2 // Iteration log. int nf = 0; int itncg = 0; int nfail = 0; printf("\n\nItn mu stepx stepz Pinf Dinf"); printf(" Cinf Objective nf center"); if (direct) { printf("\n"); } else { printf(" atol solver Inexact\n"); } double regx = (d1 * x).twoNorm(); double regy = (d2 * y).twoNorm(); // regterm = twoNorm(d1.*x)^2 + norm(d2.*y)^2; double regterm = regx * regx + regy * regy; double objreg = obj + 0.5 * regterm; double objtrue = objreg * theta; printf("\n%3g ", PDitns ); printf("%6.1f%6.1f" , log10(Pinf ), log10(Dinf)); printf("%6.1f%15.7e", log10(Cinf0), objtrue ); printf(" %8.1f\n" , center ); /* if kminor printf("\n\nStart of first minor itn...\n"); keyboard end */ //--------------------------------------------------------------------- // Main loop. //--------------------------------------------------------------------- // Lsqr ClpLsqr thisLsqr(this); // while (converged) { while(PDitns < maxitn) { PDitns = PDitns + 1; // 31 Jan 2001: Set atol according to progress, a la Inexact Newton. // 07 Feb 2001: 0.1 not small enough for Satellite problem. Try 0.01. // 25 Apr 2001: 0.01 seems wasteful for Star problem. // Now that starting conditions are better, go back to 0.1. double r3norm = CoinMax(Pinf, CoinMax(Dinf, Cinf)); atol = CoinMin(atol, r3norm * 0.1); atol = CoinMax(atol, atolmin ); info.r3norm = r3norm; //------------------------------------------------------------------- // Define a damped Newton iteration for solving f = 0, // keeping x1, x2, z1, z2 > 0. We eliminate dx1, dx2, dz1, dz2 // to obtain the system // // [-H2 A" ] [ dx ] = [ w ], H2 = H + D1^2 + X1inv Z1 + X2inv Z2, // [ A D2^2] [ dy ] = [ r1] w = r2 - X1inv(cL + Z1 rL) // + X2inv(cU + Z2 rU), // // which is equivalent to the least-squares problem // // min || [ D A"]dy - [ D w ] ||, D = H2^{-1/2}. (*) // || [ D2 ] [D2inv r1] || //------------------------------------------------------------------- for (int k = 0; k < nlow; k++) H_elts[low[k]] = H_elts[low[k]] + z1[low[k]] / x1[low[k]]; for (int k = 0; k < nupp; k++) H[upp[k]] = H[upp[k]] + z2[upp[k]] / x2[upp[k]]; w = r2; for (int k = 0; k < nlow; k++) w[low[k]] = w[low[k]] - (cL[low[k]] + z1[low[k]] * rL[low[k]]) / x1[low[k]]; for (int k = 0; k < nupp; k++) w[upp[k]] = w[upp[k]] + (cU[upp[k]] + z2[upp[k]] * rU[upp[k]]) / x2[upp[k]]; if (LSproblem == 1) { //----------------------------------------------------------------- // Solve (*) for dy. //----------------------------------------------------------------- H = 1.0 / H; // H is now Hinv (NOTE!) for (int k = 0; k < nfix; k++) H[fix[k]] = 0; for (int k = 0; k < n; k++) D_elts[k] = sqrt(H_elts[k]); thisLsqr.borrowDiag1(D_elts); thisLsqr.diag2_ = d2; if (direct) { // Omit direct option for now } else {// Iterative solve using LSQR. //rhs = [ D.*w; r1./d2 ]; for (int k = 0; k < n; k++) rhs[k] = D_elts[k] * w_elts[k]; for (int k = 0; k < m; k++) rhs[n+k] = r1_elts[k] * (1.0 / d2); double damp = 0; if (precon) { // Construct diagonal preconditioner for LSQR matPrecon(d2, Pr, D); } /* rw(7) = precon; info.atolmin = atolmin; info.r3norm = fmerit; // Must be the 2-norm here. [ dy, istop, itncg, outfo ] = ... pdxxxlsqr( nb,m,"pdxxxlsqrmat",Aname,rw,rhs,damp, ... atol,btol,conlim,itnlim,show,info ); thisLsqr.input->rhs_vec = &rhs; thisLsqr.input->sol_vec = &dy; thisLsqr.input->rel_mat_err = atol; thisLsqr.do_lsqr(this); */ // New version of lsqr int istop; dy.clear(); show = false; info.atolmin = atolmin; info.r3norm = fmerit; // Must be the 2-norm here. thisLsqr.do_lsqr( rhs, damp, atol, btol, conlim, itnlim, show, info, dy , &istop, &itncg, &outfo, precon, Pr); if (precon) dy = dy * Pr; if (!precon && itncg > 999999) precon = true; if (istop == 3 || istop == 7 ) // conlim or itnlim printf("\n LSQR stopped early: istop = //%d", istop); atolold = outfo.atolold; atol = outfo.atolnew; r3ratio = outfo.r3ratio; }// LSproblem 1 // grad = pdxxxmat( Aname,2,m,n,dy ); // grad = A"dy grad.clear(); matVecMult(2, grad, dy); for (int k = 0; k < nfix; k++) grad[fix[k]] = 0; // grad is a work vector dx = H * (grad - w); } else { perror( "This LSproblem not yet implemented\n" ); } //------------------------------------------------------------------- CGitns += itncg; //------------------------------------------------------------------- // dx and dy are now known. Get dx1, dx2, dz1, dz2. //------------------------------------------------------------------- for (int k = 0; k < nlow; k++) { dx1[low[k]] = - rL[low[k]] + dx[low[k]]; dz1[low[k]] = (cL[low[k]] - z1[low[k]] * dx1[low[k]]) / x1[low[k]]; } for (int k = 0; k < nupp; k++) { dx2[upp[k]] = - rU[upp[k]] - dx[upp[k]]; dz2[upp[k]] = (cU[upp[k]] - z2[upp[k]] * dx2[upp[k]]) / x2[upp[k]]; } //------------------------------------------------------------------- // Find the maximum step. //-------------------------------------------------------------------- double stepx1 = pdxxxstep(nlow, low, x1, dx1 ); double stepx2 = inf; if (nupp > 0) stepx2 = pdxxxstep(nupp, upp, x2, dx2 ); double stepz1 = pdxxxstep( z1 , dz1 ); double stepz2 = inf; if (nupp > 0) stepz2 = pdxxxstep( z2 , dz2 ); double stepx = CoinMin( stepx1, stepx2 ); double stepz = CoinMin( stepz1, stepz2 ); stepx = CoinMin( steptol * stepx, 1.0 ); stepz = CoinMin( steptol * stepz, 1.0 ); if (stepSame) { // For NLPs, force same step stepx = CoinMin( stepx, stepz ); // (true Newton method) stepz = stepx; } //------------------------------------------------------------------- // Backtracking linesearch. //------------------------------------------------------------------- bool fail = true; nf = 0; while (nf < maxf) { nf = nf + 1; x = x + stepx * dx; y = y + stepz * dy; for (int k = 0; k < nlow; k++) { x1[low[k]] = x1[low[k]] + stepx * dx1[low[k]]; z1[low[k]] = z1[low[k]] + stepz * dz1[low[k]]; } for (int k = 0; k < nupp; k++) { x2[upp[k]] = x2[upp[k]] + stepx * dx2[upp[k]]; z2[upp[k]] = z2[upp[k]] + stepz * dz2[upp[k]]; } // [obj,grad,hess] = feval( Fname, (x*beta) ); x.scale(beta); obj = getObj(x); getGrad(x, grad); getHessian(x, H); x.scale((1.0 / beta)); obj /= theta; grad = grad * (beta / theta) + d1 * d1 * x; H = H * (beta2 / theta) + d1 * d1; // [r1,r2,rL,rU,Pinf,Dinf] = ... pdxxxresid1( this, nlow, nupp, nfix, low, upp, fix, b, bl_elts, bu_elts, d1, d2, grad, rL, rU, x, x1, x2, y, z1, z2, r1, r2, &Pinf, &Dinf ); //double center, Cinf, Cinf0; // [cL,cU,center,Cinf,Cinf0] = ... pdxxxresid2( mu, nlow, nupp, low, upp, cL, cU, x1, x2, z1, z2, ¢er, &Cinf, &Cinf0); double fmeritnew = pdxxxmerit(nlow, nupp, low, upp, r1, r2, rL, rU, cL, cU ); double step = CoinMin( stepx, stepz ); if (fmeritnew <= (1 - eta * step)*fmerit) { fail = false; break; } // Merit function didn"t decrease. // Restore variables to previous values. // (This introduces a little error, but save lots of space.) x = x - stepx * dx; y = y - stepz * dy; for (int k = 0; k < nlow; k++) { x1[low[k]] = x1[low[k]] - stepx * dx1[low[k]]; z1[low[k]] = z1[low[k]] - stepz * dz1[low[k]]; } for (int k = 0; k < nupp; k++) { x2[upp[k]] = x2[upp[k]] - stepx * dx2[upp[k]]; z2[upp[k]] = z2[upp[k]] - stepz * dz2[upp[k]]; } // Back-track. // If it"s the first time, // make stepx and stepz the same. if (nf == 1 && stepx != stepz) { stepx = step; } else if (nf < maxf) { stepx = stepx / 2; } stepz = stepx; } if (fail) { printf("\n Linesearch failed (nf too big)"); nfail += 1; } else { nfail = 0; } //------------------------------------------------------------------- // Set convergence measures. //-------------------------------------------------------------------- regx = (d1 * x).twoNorm(); regy = (d2 * y).twoNorm(); regterm = regx * regx + regy * regy; objreg = obj + 0.5 * regterm; objtrue = objreg * theta; bool primalfeas = Pinf <= featol; bool dualfeas = Dinf <= featol; bool complementary = Cinf0 <= opttol; bool enough = PDitns >= 4; // Prevent premature termination. bool converged = primalfeas & dualfeas & complementary & enough; //------------------------------------------------------------------- // Iteration log. //------------------------------------------------------------------- char str1[100], str2[100], str3[100], str4[100], str5[100]; sprintf(str1, "\n%3g%5.1f" , PDitns , log10(mu) ); sprintf(str2, "%8.5f%8.5f" , stepx , stepz ); if (stepx < 0.0001 || stepz < 0.0001) { sprintf(str2, " %6.1e %6.1e" , stepx , stepz ); } sprintf(str3, "%6.1f%6.1f" , log10(Pinf) , log10(Dinf)); sprintf(str4, "%6.1f%15.7e", log10(Cinf0), objtrue ); sprintf(str5, "%3d%8.1f" , nf , center ); if (center > 99999) { sprintf(str5, "%3d%8.1e" , nf , center ); } printf("%s%s%s%s%s", str1, str2, str3, str4, str5); if (direct) { // relax } else { printf(" %5.1f%7d%7.3f", log10(atolold), itncg, r3ratio); } //------------------------------------------------------------------- // Test for termination. //------------------------------------------------------------------- if (kminor) { printf( "\nStart of next minor itn...\n"); // keyboard; } if (converged) { printf("\n Converged"); break; } else if (PDitns >= maxitn) { printf("\n Too many iterations"); inform = 1; break; } else if (nfail >= maxfail) { printf("\n Too many linesearch failures"); inform = 2; break; } else { // Reduce mu, and reset certain residuals. double stepmu = CoinMin( stepx , stepz ); stepmu = CoinMin( stepmu, steptol ); double muold = mu; mu = mu - stepmu * mu; if (center >= bigcenter) mu = muold; // mutrad = mu0*(sum(Xz)/n); // 24 May 1998: Traditional value, but // mu = CoinMin(mu,mutrad ); // it seemed to decrease mu too much. mu = CoinMax(mu, mulast); // 13 Jun 1998: No need for smaller mu. // [cL,cU,center,Cinf,Cinf0] = ... pdxxxresid2( mu, nlow, nupp, low, upp, cL, cU, x1, x2, z1, z2, ¢er, &Cinf, &Cinf0 ); fmerit = pdxxxmerit( nlow, nupp, low, upp, r1, r2, rL, rU, cL, cU ); // Reduce atol for LSQR (and SYMMLQ). // NOW DONE AT TOP OF LOOP. atolold = atol; // if atol > atol2 // atolfac = (mu/mufirst)^0.25; // atol = CoinMax( atol*atolfac, atol2 ); // end // atol = CoinMin( atol, mu ); // 22 Jan 2001: a la Inexact Newton. // atol = CoinMin( atol, 0.5*mu ); // 30 Jan 2001: A bit tighter // If the linesearch took more than one function (nf > 1), // we assume the search direction needed more accuracy // (though this may be true only for LPs). // 12 Jun 1998: Ask for more accuracy if nf > 2. // 24 Nov 2000: Also if the steps are small. // 30 Jan 2001: Small steps might be ok with warm start. // 06 Feb 2001: Not necessarily. Reinstated tests in next line. if (nf > 2 || CoinMin( stepx, stepz ) <= 0.01) atol = atolold * 0.1; } //--------------------------------------------------------------------- // End of main loop. //--------------------------------------------------------------------- } for (int k = 0; k < nfix; k++) x[fix[k]] = bl[fix[k]]; z = z1; if (nupp > 0) z = z - z2; printf("\n\nmax |x| =%10.3f", x.infNorm() ); printf(" max |y| =%10.3f", y.infNorm() ); printf(" max |z| =%10.3f", z.infNorm() ); printf(" scaled"); x.scale(beta); y.scale(zeta); z.scale(zeta); // Unscale x, y, z. printf( "\nmax |x| =%10.3f", x.infNorm() ); printf(" max |y| =%10.3f", y.infNorm() ); printf(" max |z| =%10.3f", z.infNorm() ); printf(" unscaled\n"); time = CoinCpuTime() - time; char str1[100], str2[100]; sprintf(str1, "\nPDitns =%10g", PDitns ); sprintf(str2, "itns =%10d", CGitns ); // printf( [str1 " " solver str2] ); printf(" time =%10.1f\n", time); /* pdxxxdistrib( abs(x),abs(z) ); // Private function if (wait) keyboard; */ //----------------------------------------------------------------------- // End function pdco.m //----------------------------------------------------------------------- /* printf("Solution x values:\n\n"); for (int k=0; k<n; k++) printf(" %d %e\n", k, x[k]); */ // Print distribution double thresh[9] = { 0.00000001, 0.0000001, 0.000001, 0.00001, 0.0001, 0.001, 0.01, 0.1, 1.00001}; int counts[9] = {0}; for (int ij = 0; ij < n; ij++) { for (int j = 0; j < 9; j++) { if(x[ij] < thresh[j]) { counts[j] += 1; break; } } } printf ("Distribution of Solution Values\n"); for (int j = 8; j > 1; j--) printf(" %g to %g %d\n", thresh[j-1], thresh[j], counts[j]); printf(" Less than %g %d\n", thresh[2], counts[0]); return inform; }
/** solve */ STO_RTN_CODE TssBd::solve() { #define FREE_MEMORY \ FREE_PTR(tssbdsub) assert(model_); /** subproblems */ const double * probability = NULL; /**< probability */ TssBdSub * tssbdsub = NULL; /**< cut generator */ double lowerbound = 0.0; BGN_TRY_CATCH /** solution time */ double swtime = CoinGetTimeOfDay(); /** time limit */ time_remains_ = par_->wtimeLimit_; /** get number of scenarios */ probability = model_->getProbability(); /** configure Benders cut generator */ /** This does NOT make deep copies. So, DO NOT RELEASE POINTERS. */ tssbdsub = new TssBdSub(par_); for (int s = 0; s < model_->getNumScenarios(); ++s) tssbdsub->scenarios_.push_back(s); STO_RTN_CHECK_THROW(tssbdsub->loadProblem(model_, naugs_, augs_, naux_), "loadProblem", "TssBdSub"); if (par_->logLevel_ > 0) printf("Phase 1:\n"); /** solution time */ double stime = clockType_ ? CoinGetTimeOfDay() : CoinCpuTime(); /** find lower bound */ /** TODO: replace this with TssDd */ STO_RTN_CHECK_THROW(findLowerBound(probability, lowerbound), "findLowerBound", "TssBd"); /** We should have a lower bound here. */ if (par_->logLevel_ > 0) printf(" -> Found lower bound %e\n", lowerbound); /** construct master problem */ STO_RTN_CHECK_THROW(constructMasterProblem(tssbdsub, lowerbound), "constructMasterProblem", "TssBd"); if (par_->logLevel_ > 0) printf("Phase 2:\n"); time_remains_ -= CoinGetTimeOfDay() - swtime; /** use L-shaped method to find lower bound */ if (model_->getNumCoreIntegers() == 0) { /** configure LP */ STO_RTN_CHECK_THROW(configureSLP(), "configureSLP", "TssBd"); /** solve LP */ STO_RTN_CHECK_THROW(solveSLP(tssbdsub), "solveSLP", "TssBd"); } else { /** configure MILP */ STO_RTN_CHECK_THROW(configureSMILP(tssbdsub), "configureSMILP", "TssBd"); /** solve MILP */ STO_RTN_CHECK_THROW(solveSMILP(), "solveSMILP", "TssBd"); } /** solution time */ solutionTime_ = (clockType_ ? CoinGetTimeOfDay() : CoinCpuTime()) - stime; /** collect solution */ switch (status_) { case STO_STAT_OPTIMAL: case STO_STAT_LIM_ITERorTIME: case STO_STAT_STOPPED_GAP: case STO_STAT_STOPPED_NODE: case STO_STAT_STOPPED_TIME: { const double * solution = si_->getSolution(); if (solution) { /** first-stage solution */ assert(solution_); CoinCopyN(solution, model_->getNumCols(0), solution_); /** second-stage solution */ double * objval_reco = new double [model_->getNumScenarios()]; double ** solution_reco = new double * [model_->getNumScenarios()]; for (int s = 0; s < model_->getNumScenarios(); ++s) solution_reco[s] = new double [model_->getNumCols(1)]; for (int s = 0; s < naugs_; ++s) CoinCopyN(solution + model_->getNumCols(0) + s * model_->getNumCols(1), model_->getNumCols(1), solution_reco[augs_[s]]); /** collect solution */ tssbdsub->solveRecourse(solution_, objval_reco, solution_reco, par_->numCores_); for (int s = 0; s < model_->getNumScenarios(); ++s) { if (tssbdsub->excludedScenarios_[s]) continue; CoinCopyN(solution_reco[s], model_->getNumCols(1), solution_ + model_->getNumCols(0) + model_->getNumCols(1) * s); } /** compute primal bound */ primalBound_ = 0.0; for (int j = 0; j < model_->getNumCols(0); ++j) primalBound_ += model_->getObjCore(0)[j] * solution_[j]; for (int s = 0; s < model_->getNumScenarios(); ++s) { primalBound_ += objval_reco[s] * model_->getProbability()[s]; } //printf("primalBound %e\n", primalBound_); /** free memory */ FREE_ARRAY_PTR(objval_reco); FREE_2D_ARRAY_PTR(model_->getNumScenarios(), solution_reco); } break; } break; default: printf("Solution status (%d).\n", status_); break; } END_TRY_CATCH_RTN(FREE_MEMORY,STO_RTN_ERR) /** free memory */ FREE_MEMORY return STO_RTN_OK; #undef FREE_MEMORY }
int main (int argc, const char *argv[]) { ClpSimplex model; int status; int maxFactor = 100; if (argc < 2) { status = model.readMps("../../Data/Netlib/czprob.mps"); if (status) { printf("Unable to read matrix - trying gzipped version\n"); status = model.readMps("../../Data/Netlib/czprob.mps.gz"); } } else { status = model.readMps(argv[1]); } if (status) { printf("errors on input\n"); exit(77); } if (argc > 2) { maxFactor = atoi(argv[2]); printf("max factor %d\n", maxFactor); } if (argc > 3) { printf("Using ClpDynamicMatrix\n"); } else { printf("Using ClpDynamicExampleMatrix\n"); } // find gub int numberRows = model.numberRows(); int * gubStart = new int[numberRows+1]; int * gubEnd = new int[numberRows]; int * which = new int[numberRows]; int * whichGub = new int[numberRows]; int numberColumns = model.numberColumns(); int * mark = new int[numberColumns]; int iRow, iColumn; // delete variables fixed to zero const double * columnLower = model.columnLower(); const double * columnUpper = model.columnUpper(); int numberDelete = 0; for (iColumn = 0; iColumn < numberColumns; iColumn++) { if (columnUpper[iColumn] == 0.0 && columnLower[iColumn] == 0.0) mark[numberDelete++] = iColumn; } if (numberDelete) { model.deleteColumns(numberDelete, mark); numberColumns -= numberDelete; columnLower = model.columnLower(); columnUpper = model.columnUpper(); } double * lower = new double[numberRows]; double * upper = new double[numberRows]; const double * rowLower = model.rowLower(); const double * rowUpper = model.rowUpper(); for (iColumn = 0; iColumn < numberColumns; iColumn++) mark[iColumn] = -1; CoinPackedMatrix * matrix = model.matrix(); // get row copy CoinPackedMatrix rowCopy = *matrix; rowCopy.reverseOrdering(); const int * column = rowCopy.getIndices(); const int * rowLength = rowCopy.getVectorLengths(); const CoinBigIndex * rowStart = rowCopy.getVectorStarts(); const double * element = rowCopy.getElements(); int putGub = numberRows; int putNonGub = numberRows; int * rowIsGub = new int [numberRows]; for (iRow = numberRows - 1; iRow >= 0; iRow--) { bool gubRow = true; int first = numberColumns + 1; int last = -1; for (int j = rowStart[iRow]; j < rowStart[iRow] + rowLength[iRow]; j++) { if (element[j] != 1.0) { gubRow = false; break; } else { int iColumn = column[j]; if (mark[iColumn] >= 0) { gubRow = false; break; } else { last = CoinMax(last, iColumn); first = CoinMin(first, iColumn); } } } if (last - first + 1 != rowLength[iRow] || !gubRow) { which[--putNonGub] = iRow; rowIsGub[iRow] = 0; } else { for (int j = rowStart[iRow]; j < rowStart[iRow] + rowLength[iRow]; j++) { int iColumn = column[j]; mark[iColumn] = iRow; } rowIsGub[iRow] = -1; putGub--; gubStart[putGub] = first; gubEnd[putGub] = last + 1; lower[putGub] = rowLower[iRow]; upper[putGub] = rowUpper[iRow]; whichGub[putGub] = iRow; } } int numberNonGub = numberRows - putNonGub; int numberGub = numberRows - putGub; if (numberGub > 0) { printf("** %d gub rows\n", numberGub); int numberNormal = 0; const int * row = matrix->getIndices(); const int * columnLength = matrix->getVectorLengths(); const CoinBigIndex * columnStart = matrix->getVectorStarts(); const double * elementByColumn = matrix->getElements(); int numberElements = 0; bool doLower = false; bool doUpper = false; for (iColumn = 0; iColumn < numberColumns; iColumn++) { if (mark[iColumn] < 0) { mark[numberNormal++] = iColumn; } else { numberElements += columnLength[iColumn]; if (columnLower[iColumn] != 0.0) doLower = true; if (columnUpper[iColumn] < 1.0e20) doUpper = true; } } if (!numberNormal) { printf("Putting back one gub row to make non-empty\n"); for (iColumn = gubStart[putGub]; iColumn < gubEnd[putGub]; iColumn++) mark[numberNormal++] = iColumn; putGub++; numberGub--; } ClpSimplex model2(&model, numberNonGub, which + putNonGub, numberNormal, mark); // and copy for restart test ClpSimplex model3 = model2; int numberGubColumns = numberColumns - numberNormal; // sort gubs so monotonic int * which = new int[numberGub]; int i; for (i = 0; i < numberGub; i++) which[i] = i; CoinSort_2(gubStart + putGub, gubStart + putGub + numberGub, which); // move to bottom if we want to use later memmove(gubStart, gubStart + putGub, numberGub * sizeof(int)); int * temp1 = new int [numberGub]; for (i = 0; i < numberGub; i++) { int k = which[i]; temp1[i] = gubEnd[putGub+k]; } memcpy(gubEnd, temp1, numberGub * sizeof(int)); delete [] temp1; double * temp2 = new double [numberGub]; for (i = 0; i < numberGub; i++) { int k = which[i]; temp2[i] = lower[putGub+k]; } memcpy(lower, temp2, numberGub * sizeof(double)); for (i = 0; i < numberGub; i++) { int k = which[i]; temp2[i] = upper[putGub+k]; } memcpy(upper, temp2, numberGub * sizeof(double)); delete [] temp2; delete [] which; numberElements -= numberGubColumns; int * start2 = new int[numberGubColumns+1]; int * row2 = new int[numberElements]; double * element2 = new double[numberElements]; double * cost2 = new double [numberGubColumns]; double * lowerColumn2 = NULL; if (doLower) { lowerColumn2 = new double [numberGubColumns]; CoinFillN(lowerColumn2, numberGubColumns, 0.0); } double * upperColumn2 = NULL; if (doUpper) { upperColumn2 = new double [numberGubColumns]; CoinFillN(upperColumn2, numberGubColumns, COIN_DBL_MAX); } numberElements = 0; int numberNonGubRows = 0; for (iRow = 0; iRow < numberRows; iRow++) { if (!rowIsGub[iRow]) rowIsGub[iRow] = numberNonGubRows++; } numberColumns = 0; int iStart = gubStart[0]; gubStart[0] = 0; start2[0] = 0; const double * cost = model.objective(); for (int iSet = 0; iSet < numberGub; iSet++) { int iEnd = gubEnd[iSet]; for (int k = iStart; k < iEnd; k++) { cost2[numberColumns] = cost[k]; if (columnLower[k]) lowerColumn2[numberColumns] = columnLower[k]; if (columnUpper[k] < 1.0e20) upperColumn2[numberColumns] = columnUpper[k]; for (int j = columnStart[k]; j < columnStart[k] + columnLength[k]; j++) { int iRow = rowIsGub[row[j]]; if (iRow >= 0) { row2[numberElements] = iRow; element2[numberElements++] = elementByColumn[j]; } } start2[++numberColumns] = numberElements; } if (iSet < numberGub - 1) iStart = gubStart[iSet+1]; gubStart[iSet+1] = numberColumns; } printf("** Before adding matrix there are %d rows and %d columns\n", model2.numberRows(), model2.numberColumns()); if (argc > 3) { ClpDynamicMatrix * newMatrix = new ClpDynamicMatrix(&model2, numberGub, numberColumns, gubStart, lower, upper, start2, row2, element2, cost2, lowerColumn2, upperColumn2); model2.replaceMatrix(newMatrix); newMatrix->switchOffCheck(); newMatrix->setRefreshFrequency(1000); } else { ClpDynamicExampleMatrix * newMatrix = new ClpDynamicExampleMatrix(&model2, numberGub, numberColumns, gubStart, lower, upper, start2, row2, element2, cost2, lowerColumn2, upperColumn2); model2.replaceMatrix(newMatrix); newMatrix->switchOffCheck(); newMatrix->setRefreshFrequency(1000); } printf("** While after adding matrix there are %d rows and %d columns\n", model2.numberRows(), model2.numberColumns()); model2.setSpecialOptions(4); // exactly to bound // For now scaling off model2.scaling(0); ClpPrimalColumnSteepest steepest(5); model2.setPrimalColumnPivotAlgorithm(steepest); //model2.messageHandler()->setLogLevel(63); model2.setFactorizationFrequency(maxFactor); model2.setMaximumIterations(4000000); double time1 = CoinCpuTime(); model2.primal(); // can't use values pass model2.primal(0); // test proper restart if (argc > 3) { ClpDynamicMatrix * oldMatrix = dynamic_cast< ClpDynamicMatrix*>(model2.clpMatrix()); assert (oldMatrix); ClpDynamicMatrix * newMatrix = new ClpDynamicMatrix(&model3, numberGub, numberColumns, gubStart, lower, upper, start2, row2, element2, cost2, lowerColumn2, upperColumn2, oldMatrix->gubRowStatus(), oldMatrix->dynamicStatus()); model3.replaceMatrix(newMatrix); // and ordinary status (but only NON gub rows) memcpy(model3.statusArray(), model2.statusArray(), (newMatrix->numberStaticRows() + model3.numberColumns())*sizeof(unsigned char)); newMatrix->switchOffCheck(); newMatrix->setRefreshFrequency(1000); } else { ClpDynamicExampleMatrix * oldMatrix = dynamic_cast< ClpDynamicExampleMatrix*>(model2.clpMatrix()); assert (oldMatrix); ClpDynamicExampleMatrix * newMatrix = new ClpDynamicExampleMatrix(&model3, numberGub, numberColumns, gubStart, lower, upper, start2, row2, element2, cost2, lowerColumn2, upperColumn2, oldMatrix->gubRowStatus(), oldMatrix->dynamicStatus(), oldMatrix->numberGubColumns(), oldMatrix->idGen()); model3.replaceMatrix(newMatrix); // and ordinary status (but only NON gub rows) memcpy(model3.statusArray(), model2.statusArray(), (newMatrix->numberStaticRows() + model3.numberColumns())*sizeof(unsigned char)); newMatrix->switchOffCheck(); newMatrix->setRefreshFrequency(1000); } model3.setSpecialOptions(4); // exactly to bound // For now scaling off model3.scaling(0); model3.setPrimalColumnPivotAlgorithm(steepest); model3.messageHandler()->setLogLevel(63); model3.setFactorizationFrequency(maxFactor); model3.setMaximumIterations(4000000); delete [] rowIsGub; delete [] start2; delete [] row2; delete [] element2; delete [] cost2; delete [] lowerColumn2; delete [] upperColumn2; model3.primal(); // this code expects non gub first in original matrix // and only works at present for ClpDynamicMatrix ClpDynamicMatrix * gubMatrix = dynamic_cast< ClpDynamicMatrix*>(model2.clpMatrix()); assert (gubMatrix); ClpDynamicExampleMatrix * gubMatrix2 = dynamic_cast< ClpDynamicExampleMatrix*>(model2.clpMatrix()); if (!gubMatrix2) { const double * solution = model2.primalColumnSolution(); const double * cost = model.objective(); int numberGubColumns = gubMatrix->numberGubColumns(); int firstOdd = gubMatrix->firstDynamic(); int lastOdd = gubMatrix->firstAvailable(); int numberTotalColumns = firstOdd + numberGubColumns; int originalNumberRows = model.numberRows(); int numberStaticRows = gubMatrix->numberStaticRows(); char * status = new char [numberTotalColumns]; double * gubSolution = new double [numberTotalColumns]; int numberSets = gubMatrix->numberSets(); const int * id = gubMatrix->id(); int i; const float * columnLower = gubMatrix->columnLower(); const float * columnUpper = gubMatrix->columnUpper(); for (i = 0; i < numberGubColumns; i++) { if (gubMatrix->getDynamicStatus(i) == ClpDynamicMatrix::atUpperBound) { gubSolution[i+firstOdd] = columnUpper[i]; status[i+firstOdd] = 2; } else if (gubMatrix->getDynamicStatus(i) == ClpDynamicMatrix::atLowerBound && columnLower) { gubSolution[i+firstOdd] = columnLower[i]; status[i+firstOdd] = 1; } else if (gubMatrix->getDynamicStatus(i) == ClpDynamicMatrix::soloKey) { int iSet = gubMatrix->whichSet(i); gubSolution[i+firstOdd] = gubMatrix->keyValue(iSet); status[i+firstOdd] = 0; } else { gubSolution[i+firstOdd] = 0.0; status[i+firstOdd] = 1; } } for (i = 0; i < firstOdd; i++) { ClpSimplex::Status thisStatus = model2.getStatus(i); if (thisStatus == ClpSimplex::basic) status[i] = 0; else if (thisStatus == ClpSimplex::atLowerBound) status[i] = 1; else if (thisStatus == ClpSimplex::atUpperBound) status[i] = 2; else if (thisStatus == ClpSimplex::isFixed) status[i] = 3; else abort(); gubSolution[i] = solution[i]; } for (i = firstOdd; i < lastOdd; i++) { int iBig = id[i-firstOdd] + firstOdd; ClpSimplex::Status thisStatus = model2.getStatus(i); if (thisStatus == ClpSimplex::basic) status[iBig] = 0; else if (thisStatus == ClpSimplex::atLowerBound) status[iBig] = 1; else if (thisStatus == ClpSimplex::atUpperBound) status[iBig] = 2; else if (thisStatus == ClpSimplex::isFixed) status[iBig] = 3; else abort(); gubSolution[iBig] = solution[i]; } char * rowStatus = new char[originalNumberRows]; for (i = 0; i < numberStaticRows; i++) { ClpSimplex::Status thisStatus = model2.getRowStatus(i); if (thisStatus == ClpSimplex::basic) rowStatus[i] = 0; else if (thisStatus == ClpSimplex::atLowerBound) rowStatus[i] = 1; else if (thisStatus == ClpSimplex::atUpperBound) rowStatus[i] = 2; else if (thisStatus == ClpSimplex::isFixed) rowStatus[i] = 3; else abort(); } double objValue = 0.0; for (i = 0; i < numberTotalColumns; i++) objValue += cost[i] * gubSolution[i]; printf("objective value is %g\n", objValue); for (i = 0; i < numberSets; i++) { ClpSimplex::Status thisStatus = gubMatrix->getStatus(i); if (thisStatus == ClpSimplex::basic) rowStatus[numberStaticRows+i] = 0; else if (thisStatus == ClpSimplex::atLowerBound) rowStatus[numberStaticRows+i] = 1; else if (thisStatus == ClpSimplex::atUpperBound) rowStatus[numberStaticRows+i] = 2; else if (thisStatus == ClpSimplex::isFixed) rowStatus[numberStaticRows+i] = 3; else abort(); } // Coding below may not work if gub rows not at end FILE * fp = fopen ("xx.sol", "w"); fwrite(gubSolution, sizeof(double), numberTotalColumns, fp); fwrite(status, sizeof(char), numberTotalColumns, fp); const double * rowsol = model2.primalRowSolution(); double * rowsol2 = new double[originalNumberRows]; memset(rowsol2, 0, originalNumberRows * sizeof(double)); model.times(1.0, gubSolution, rowsol2); for (i = 0; i < numberStaticRows; i++) assert (fabs(rowsol[i] - rowsol2[i]) < 1.0e-3); for (; i < originalNumberRows; i++) assert (rowsol2[i] > lower[i-numberStaticRows] - 1.0e-3 && rowsol2[i] < upper[i-numberStaticRows] + 1.0e-3); //for (;i<originalNumberRows;i++) //printf("%d %g\n",i,rowsol2[i]); fwrite(rowsol2, sizeof(double), originalNumberRows, fp); delete [] rowsol2; fwrite(rowStatus, sizeof(char), originalNumberRows, fp); fclose(fp); delete [] status; delete [] gubSolution; // ** if going to rstart as dynamic need id_ // also copy coding in useEf.. from ClpGubMatrix (i.e. test for basis) } printf("obj offset is %g\n", model2.objectiveOffset()); printf("Primal took %g seconds\n", CoinCpuTime() - time1); } delete [] mark; delete [] gubStart; delete [] gubEnd; delete [] which; delete [] whichGub; delete [] lower; delete [] upper; return 0; }
int main(int argc, const char *argv[]) { try { // Empty model ClpSimplex model; // Objective - just nonzeros int objIndex[] = {0, 2}; double objValue[] = {1.0, 4.0}; // Upper bounds - as dense vector double upper[] = {2.0, COIN_DBL_MAX, 4.0}; // Create space for 3 columns model.resize(0, 3); // Fill in int i; // Virtuous way // First objective for (i = 0; i < 2; i++) model.setObjectiveCoefficient(objIndex[i], objValue[i]); // Now bounds (lower will be zero by default but do again) for (i = 0; i < 3; i++) { model.setColumnLower(i, 0.0); model.setColumnUpper(i, upper[i]); } /* We could also have done in non-virtuous way e.g. double * objective = model.objective(); and then set directly */ // Faster to add rows all at once - but this is easier to show // Now add row 1 as >= 2.0 int row1Index[] = {0, 2}; double row1Value[] = {1.0, 1.0}; model.addRow(2, row1Index, row1Value, 2.0, COIN_DBL_MAX); // Now add row 2 as == 1.0 int row2Index[] = {0, 1, 2}; double row2Value[] = {1.0, -5.0, 1.0}; model.addRow(3, row2Index, row2Value, 1.0, 1.0); // solve model.dual(); /* Adding one row at a time has a significant overhead so let's try a more complicated but faster way First time adding in 10000 rows one by one */ model.allSlackBasis(); ClpSimplex modelSave = model; double time1 = CoinCpuTime(); int k; for (k = 0; k < 10000; k++) { int row2Index[] = {0, 1, 2}; double row2Value[] = {1.0, -5.0, 1.0}; model.addRow(3, row2Index, row2Value, 1.0, 1.0); } printf("Time for 10000 addRow is %g\n", CoinCpuTime() - time1); model.dual(); model = modelSave; // Now use build CoinBuild buildObject; time1 = CoinCpuTime(); for (k = 0; k < 10000; k++) { int row2Index[] = {0, 1, 2}; double row2Value[] = {1.0, -5.0, 1.0}; buildObject.addRow(3, row2Index, row2Value, 1.0, 1.0); } model.addRows(buildObject); printf("Time for 10000 addRow using CoinBuild is %g\n", CoinCpuTime() - time1); model.dual(); model = modelSave; int del[] = {0, 1, 2}; model.deleteRows(2, del); // Now use build +-1 CoinBuild buildObject2; time1 = CoinCpuTime(); for (k = 0; k < 10000; k++) { int row2Index[] = {0, 1, 2}; double row2Value[] = {1.0, -1.0, 1.0}; buildObject2.addRow(3, row2Index, row2Value, 1.0, 1.0); } model.addRows(buildObject2, true); printf("Time for 10000 addRow using CoinBuild+-1 is %g\n", CoinCpuTime() - time1); model.dual(); model = modelSave; model.deleteRows(2, del); // Now use build +-1 CoinModel modelObject2; time1 = CoinCpuTime(); for (k = 0; k < 10000; k++) { int row2Index[] = {0, 1, 2}; double row2Value[] = {1.0, -1.0, 1.0}; modelObject2.addRow(3, row2Index, row2Value, 1.0, 1.0); } model.addRows(modelObject2, true); printf("Time for 10000 addRow using CoinModel+-1 is %g\n", CoinCpuTime() - time1); model.dual(); model = ClpSimplex(); // Now use build +-1 CoinModel modelObject3; time1 = CoinCpuTime(); for (k = 0; k < 10000; k++) { int row2Index[] = {0, 1, 2}; double row2Value[] = {1.0, -1.0, 1.0}; modelObject3.addRow(3, row2Index, row2Value, 1.0, 1.0); } model.loadProblem(modelObject3, true); printf("Time for 10000 addRow using CoinModel load +-1 is %g\n", CoinCpuTime() - time1); model.writeMps("xx.mps"); model.dual(); model = modelSave; // Now use model CoinModel modelObject; time1 = CoinCpuTime(); for (k = 0; k < 10000; k++) { int row2Index[] = {0, 1, 2}; double row2Value[] = {1.0, -5.0, 1.0}; modelObject.addRow(3, row2Index, row2Value, 1.0, 1.0); } model.addRows(modelObject); printf("Time for 10000 addRow using CoinModel is %g\n", CoinCpuTime() - time1); model.dual(); model.writeMps("b.mps"); // Method using least memory - but most complicated time1 = CoinCpuTime(); // Assumes we know exact size of model and matrix // Empty model ClpSimplex model2; { // Create space for 3 columns and 10000 rows int numberRows = 10000; int numberColumns = 3; // This is fully dense - but would not normally be so int numberElements = numberRows * numberColumns; // Arrays will be set to default values model2.resize(numberRows, numberColumns); double * elements = new double [numberElements]; CoinBigIndex * starts = new CoinBigIndex [numberColumns+1]; int * rows = new int [numberElements];; int * lengths = new int[numberColumns]; // Now fill in - totally unsafe but .... // no need as defaults to 0.0 double * columnLower = model2.columnLower(); double * columnUpper = model2.columnUpper(); double * objective = model2.objective(); double * rowLower = model2.rowLower(); double * rowUpper = model2.rowUpper(); // Columns - objective was packed for (k = 0; k < 2; k++) { int iColumn = objIndex[k]; objective[iColumn] = objValue[k]; } for (k = 0; k < numberColumns; k++) columnUpper[k] = upper[k]; // Rows for (k = 0; k < numberRows; k++) { rowLower[k] = 1.0; rowUpper[k] = 1.0; } // Now elements double row2Value[] = {1.0, -5.0, 1.0}; CoinBigIndex put = 0; for (k = 0; k < numberColumns; k++) { starts[k] = put; lengths[k] = numberRows; double value = row2Value[k]; for (int i = 0; i < numberRows; i++) { rows[put] = i; elements[put] = value; put++; } } starts[numberColumns] = put; // assign to matrix CoinPackedMatrix * matrix = new CoinPackedMatrix(true, 0.0, 0.0); matrix->assignMatrix(true, numberRows, numberColumns, numberElements, elements, rows, starts, lengths); ClpPackedMatrix * clpMatrix = new ClpPackedMatrix(matrix); model2.replaceMatrix(clpMatrix, true); printf("Time for 10000 addRow using hand written code is %g\n", CoinCpuTime() - time1); // If matrix is really big could switch off creation of row copy // model2.setSpecialOptions(256); } model2.dual(); model2.writeMps("a.mps"); // Print column solution int numberColumns = model.numberColumns(); // Alternatively getColSolution() double * columnPrimal = model.primalColumnSolution(); // Alternatively getReducedCost() double * columnDual = model.dualColumnSolution(); // Alternatively getColLower() double * columnLower = model.columnLower(); // Alternatively getColUpper() double * columnUpper = model.columnUpper(); // Alternatively getObjCoefficients() double * columnObjective = model.objective(); int iColumn; std::cout << " Primal Dual Lower Upper Cost" << std::endl; for (iColumn = 0; iColumn < numberColumns; iColumn++) { double value; std::cout << std::setw(6) << iColumn << " "; value = columnPrimal[iColumn]; if (fabs(value) < 1.0e5) std::cout << setiosflags(std::ios::fixed | std::ios::showpoint) << std::setw(14) << value; else std::cout << setiosflags(std::ios::scientific) << std::setw(14) << value; value = columnDual[iColumn]; if (fabs(value) < 1.0e5) std::cout << setiosflags(std::ios::fixed | std::ios::showpoint) << std::setw(14) << value; else std::cout << setiosflags(std::ios::scientific) << std::setw(14) << value; value = columnLower[iColumn]; if (fabs(value) < 1.0e5) std::cout << setiosflags(std::ios::fixed | std::ios::showpoint) << std::setw(14) << value; else std::cout << setiosflags(std::ios::scientific) << std::setw(14) << value; value = columnUpper[iColumn]; if (fabs(value) < 1.0e5) std::cout << setiosflags(std::ios::fixed | std::ios::showpoint) << std::setw(14) << value; else std::cout << setiosflags(std::ios::scientific) << std::setw(14) << value; value = columnObjective[iColumn]; if (fabs(value) < 1.0e5) std::cout << setiosflags(std::ios::fixed | std::ios::showpoint) << std::setw(14) << value; else std::cout << setiosflags(std::ios::scientific) << std::setw(14) << value; std::cout << std::endl; } std::cout << "--------------------------------------" << std::endl; // Test CoinAssert std::cout << "If Clp compiled without NDEBUG below should give assert, if with NDEBUG or COIN_ASSERT CoinError" << std::endl; model = modelSave; model.deleteRows(2, del); // Deliberate error model.deleteColumns(1, del + 2); // Now use build +-1 CoinBuild buildObject3; time1 = CoinCpuTime(); for (k = 0; k < 10000; k++) { int row2Index[] = {0, 1, 2}; double row2Value[] = {1.0, -1.0, 1.0}; buildObject3.addRow(3, row2Index, row2Value, 1.0, 1.0); } model.addRows(buildObject3, true); } catch (CoinError e) { e.print(); if (e.lineNumber() >= 0) std::cout << "This was from a CoinAssert" << std::endl; } 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; }
/************************************************************************ This main program reads in an integer model from an mps file. It then replaces all 0-1 variables by lotsizing variables which can take values 0.0,0.45-0.55 or 1.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(MIPLIB3DIR) mpsFileName = MIPLIB3DIR "/10teams"; #else if (argc < 2) { fprintf(stderr, "Do not know where to find miplib3 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; } int iColumn; int numberColumns = solver1.getNumCols(); int numberLot=0; char * mark = new char[numberColumns]; // take off integers but find where they are for (iColumn=0;iColumn<numberColumns;iColumn++) { if (solver1.isBinary(iColumn)) { solver1.setContinuous(iColumn); mark[iColumn]=1; numberLot++; } else { mark[iColumn]=0; } } CbcModel model(solver1); // Do lotsizing CbcObject ** objects = new CbcObject * [numberLot]; numberLot=0; /* For semi-continuous variables numberRanges is 2 and ranges[]={0.0,0.0,K,COIN_DBL_MAX}; */ // valid ranges are 0.0 to 0.0, 0.45 to 0.55, 1.0 to 1.0 double ranges[]={0.0,0.0,0.45,0.55,1.0,1.0}; for (iColumn=0;iColumn<numberColumns;iColumn++) { if (mark[iColumn]) objects[numberLot++]= new CbcLotsize(&model,iColumn,3,ranges,true); } delete [] mark; model.addObjects(numberLot,objects); for (iColumn=0;iColumn<numberLot;iColumn++) delete objects[iColumn]; delete [] objects; // 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 model.solver()->setHintParam(OsiDoReducePrint,true,OsiHintTry); 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(1); double 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; // Print solution - 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) 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; }
const CoinPresolveAction *forcing_constraint_action::presolve(CoinPresolveMatrix *prob, const CoinPresolveAction *next) { double startTime = 0.0; int startEmptyRows=0; int startEmptyColumns = 0; if (prob->tuning_) { startTime = CoinCpuTime(); startEmptyRows = prob->countEmptyRows(); startEmptyColumns = prob->countEmptyCols(); } double *clo = prob->clo_; double *cup = prob->cup_; double *csol = prob->sol_ ; const double *rowels = prob->rowels_; const int *hcol = prob->hcol_; const CoinBigIndex *mrstrt = prob->mrstrt_; const int *hinrow = prob->hinrow_; const int nrows = prob->nrows_; const double *rlo = prob->rlo_; const double *rup = prob->rup_; // const char *integerType = prob->integerType_; const double tol = ZTOLDP; const double inftol = prob->feasibilityTolerance_; const int ncols = prob->ncols_; int *fixed_cols = new int[ncols]; int nfixed_cols = 0; action *actions = new action [nrows]; int nactions = 0; int *useless_rows = new int[nrows]; int nuseless_rows = 0; int numberLook = prob->numberRowsToDo_; int iLook; int * look = prob->rowsToDo_; bool fixInfeasibility = (prob->presolveOptions_&16384)!=0; # if PRESOLVE_DEBUG std::cout << "Entering forcing_constraint_action::presolve." << std::endl ; presolve_check_sol(prob) ; # endif /* Open a loop to scan the constraints of interest. There must be variables left in the row. */ for (iLook=0;iLook<numberLook;iLook++) { int irow = look[iLook]; if (hinrow[irow] > 0) { CoinBigIndex krs = mrstrt[irow]; CoinBigIndex kre = krs + hinrow[irow]; /* Calculate upper and lower bounds on the row activity based on upper and lower bounds on the variables. If these are finite and incompatible with the given row bounds, we have infeasibility. */ double maxup, maxdown; implied_row_bounds(rowels, clo, cup, hcol, krs, kre, &maxup, &maxdown); if (maxup < PRESOLVE_INF && maxup + inftol < rlo[irow]&&!fixInfeasibility) { /* max row activity below the row lower bound */ prob->status_|= 1; prob->messageHandler()->message(COIN_PRESOLVE_ROWINFEAS, prob->messages()) <<irow <<rlo[irow] <<rup[irow] <<CoinMessageEol; break; } else if (-PRESOLVE_INF < maxdown && rup[irow] < maxdown - inftol&&!fixInfeasibility) { /* min row activity above the row upper bound */ prob->status_|= 1; prob->messageHandler()->message(COIN_PRESOLVE_ROWINFEAS, prob->messages()) <<irow <<rlo[irow] <<rup[irow] <<CoinMessageEol; break; } // ADD TOLERANCE TO THESE TESTS else if ((rlo[irow] <= -PRESOLVE_INF || (-PRESOLVE_INF < maxdown && rlo[irow] <= maxdown)) && (rup[irow] >= PRESOLVE_INF || (maxup < PRESOLVE_INF && rup[irow] >= maxup))) { /* Original comment: I'm not sure that these transforms don't intefere with each other. We can get it next time. Well, I'll argue that bounds are never really loosened (at worst, they're transferred onto some other variable, or inferred to be unnecessary. Once useless, always useless. Leaving this hook in place allows for a sort of infinite loop where this routine keeps queuing the same constraints over and over. -- lh, 040901 -- if (some_col_was_fixed(hcol, krs, kre, clo, cup)) { prob->addRow(irow); continue; } */ // this constraint must always be satisfied - drop it useless_rows[nuseless_rows++] = irow; } else if ((maxup < PRESOLVE_INF && fabs(rlo[irow] - maxup) < tol) || (-PRESOLVE_INF < maxdown && fabs(rup[irow] - maxdown) < tol)) { // the lower bound can just be reached, or // the upper bound can just be reached; // called a "forcing constraint" in the paper (p. 226) const int lbound_tight = (maxup < PRESOLVE_INF && fabs(rlo[irow] - maxup) < tol); /* Original comment and rebuttal as above. if (some_col_was_fixed(hcol, krs, kre, clo, cup)) { // make sure on next time prob->addRow(irow); continue; } */ // out of space - this probably never happens (but this routine will // often put duplicates in the fixed column list) if (nfixed_cols + (kre-krs) >= ncols) break; double *bounds = new double[hinrow[irow]]; int *rowcols = new int[hinrow[irow]]; int lk = krs; // load fix-to-down in front int uk = kre; // load fix-to-up in back CoinBigIndex k; for ( k=krs; k<kre; k++) { int jcol = hcol[k]; prob->addCol(jcol); double coeff = rowels[k]; PRESOLVEASSERT(fabs(coeff) > ZTOLDP); // one of the two contributed to maxup - set the other to that if (lbound_tight == (coeff > 0.0)) { --uk; bounds[uk-krs] = clo[jcol]; rowcols[uk-krs] = jcol; if (csol != 0) { csol[jcol] = cup[jcol] ; } clo[jcol] = cup[jcol]; } else { bounds[lk-krs] = cup[jcol]; rowcols[lk-krs] = jcol; ++lk; if (csol != 0) { csol[jcol] = clo[jcol] ; } cup[jcol] = clo[jcol]; } fixed_cols[nfixed_cols++] = jcol; } PRESOLVEASSERT(uk == lk); action *f = &actions[nactions]; nactions++; f->row = irow; f->nlo = lk-krs; f->nup = kre-uk; f->rowcols = rowcols; f->bounds = bounds; } } } if (nactions) { #if PRESOLVE_SUMMARY printf("NFORCED: %d\n", nactions); #endif next = new forcing_constraint_action(nactions, CoinCopyOfArray(actions,nactions), next); } deleteAction(actions,action*); if (nuseless_rows) { next = useless_constraint_action::presolve(prob, useless_rows, nuseless_rows, next); } delete[]useless_rows; /* We need to remove duplicates here, or we get into trouble in remove_fixed_action::postsolve when we try to reinstate a column multiple times. */ if (nfixed_cols) { if (nfixed_cols > 1) { std::sort(fixed_cols,fixed_cols+nfixed_cols) ; int *end = std::unique(fixed_cols,fixed_cols+nfixed_cols) ; nfixed_cols = static_cast<int>(end-fixed_cols) ; } next = remove_fixed_action::presolve(prob,fixed_cols,nfixed_cols,next) ; } delete[]fixed_cols ; if (prob->tuning_) { double thisTime=CoinCpuTime(); int droppedRows = prob->countEmptyRows() - startEmptyRows ; int droppedColumns = prob->countEmptyCols() - startEmptyColumns; printf("CoinPresolveForcing(32) - %d rows, %d columns dropped in time %g, total %g\n", droppedRows,droppedColumns,thisTime-startTime,thisTime-prob->startTime_); } # if PRESOLVE_DEBUG presolve_check_sol(prob) ; std::cout << "Leaving forcing_constraint_action::presolve." << std::endl ; # endif return (next); }
int main(int argc, const char *argv[]) { ClpSimplex model; int status; // Keep names if (argc < 2) { status = model.readMps("small.mps", true); } else { status = model.readMps(argv[1], false); } if (status) exit(10); /* This driver implements a method of treating a problem as all cuts. So it adds in all E rows, solves and then adds in violated rows. */ double time1 = CoinCpuTime(); ClpSimplex * model2; ClpPresolve pinfo; int numberPasses = 5; // can change this /* Use a tolerance of 1.0e-8 for feasibility, treat problem as not being integer, do "numberpasses" passes and throw away names in presolved model */ model2 = pinfo.presolvedModel(model, 1.0e-8, false, numberPasses, false); if (!model2) { fprintf(stderr, "ClpPresolve says %s is infeasible with tolerance of %g\n", argv[1], 1.0e-8); fprintf(stdout, "ClpPresolve says %s is infeasible with tolerance of %g\n", argv[1], 1.0e-8); // model was infeasible - maybe try again with looser tolerances model2 = pinfo.presolvedModel(model, 1.0e-7, false, numberPasses, false); if (!model2) { fprintf(stderr, "ClpPresolve says %s is infeasible with tolerance of %g\n", argv[1], 1.0e-7); fprintf(stdout, "ClpPresolve says %s is infeasible with tolerance of %g\n", argv[1], 1.0e-7); exit(2); } } // change factorization frequency from 200 model2->setFactorizationFrequency(100 + model2->numberRows() / 50); int numberColumns = model2->numberColumns(); int originalNumberRows = model2->numberRows(); // We will need arrays to choose rows to add double * weight = new double [originalNumberRows]; int * sort = new int [originalNumberRows]; int numberSort = 0; char * take = new char [originalNumberRows]; const double * rowLower = model2->rowLower(); const double * rowUpper = model2->rowUpper(); int iRow, iColumn; // Set up initial list numberSort = 0; for (iRow = 0; iRow < originalNumberRows; iRow++) { weight[iRow] = 1.123e50; if (rowLower[iRow] == rowUpper[iRow]) { sort[numberSort++] = iRow; weight[iRow] = 0.0; } } numberSort /= 2; // Just add this number of rows each time in small problem int smallNumberRows = 2 * numberColumns; smallNumberRows = CoinMin(smallNumberRows, originalNumberRows / 20); // and pad out with random rows double ratio = ((double)(smallNumberRows - numberSort)) / ((double) originalNumberRows); for (iRow = 0; iRow < originalNumberRows; iRow++) { if (weight[iRow] == 1.123e50 && CoinDrand48() < ratio) sort[numberSort++] = iRow; } /* This is optional. The best thing to do is to miss out random rows and do a set which makes dual feasible. If that is not possible then make sure variables have bounds. One way that normally works is to automatically tighten bounds. */ #if 0 // However for some we need to do anyway double * columnLower = model2->columnLower(); double * columnUpper = model2->columnUpper(); for (iColumn = 0; iColumn < numberColumns; iColumn++) { columnLower[iColumn] = CoinMax(-1.0e6, columnLower[iColumn]); columnUpper[iColumn] = CoinMin(1.0e6, columnUpper[iColumn]); } #endif model2->tightenPrimalBounds(-1.0e4, true); printf("%d rows in initial problem\n", numberSort); double * fullSolution = model2->primalRowSolution(); // Just do this number of passes int maxPass = 50; // And take out slack rows until this pass int takeOutPass = 30; int iPass; const int * start = model2->clpMatrix()->getVectorStarts(); const int * length = model2->clpMatrix()->getVectorLengths(); const int * row = model2->clpMatrix()->getIndices(); int * whichColumns = new int [numberColumns]; for (iColumn = 0; iColumn < numberColumns; iColumn++) whichColumns[iColumn] = iColumn; int numberSmallColumns = numberColumns; for (iPass = 0; iPass < maxPass; iPass++) { printf("Start of pass %d\n", iPass); // Cleaner this way std::sort(sort, sort + numberSort); // Create small problem ClpSimplex small(model2, numberSort, sort, numberSmallColumns, whichColumns); small.setFactorizationFrequency(100 + numberSort / 200); //small.setPerturbation(50); //small.setLogLevel(63); // A variation is to just do N iterations //if (iPass) //small.setMaximumIterations(100); // Solve small.factorization()->messageLevel(8); if (iPass) { small.dual(); } else { small.writeMps("continf.mps"); ClpSolve solveOptions; solveOptions.setSolveType(ClpSolve::useDual); //solveOptions.setSolveType(ClpSolve::usePrimalorSprint); //solveOptions.setSpecialOption(1,2,200); // idiot small.initialSolve(solveOptions); } bool dualInfeasible = (small.status() == 2); // move solution back double * solution = model2->primalColumnSolution(); const double * smallSolution = small.primalColumnSolution(); for (int j = 0; j < numberSmallColumns; j++) { iColumn = whichColumns[j]; solution[iColumn] = smallSolution[j]; model2->setColumnStatus(iColumn, small.getColumnStatus(j)); } for (iRow = 0; iRow < numberSort; iRow++) { int kRow = sort[iRow]; model2->setRowStatus(kRow, small.getRowStatus(iRow)); } // compute full solution memset(fullSolution, 0, originalNumberRows * sizeof(double)); model2->times(1.0, model2->primalColumnSolution(), fullSolution); if (iPass != maxPass - 1) { // Mark row as not looked at for (iRow = 0; iRow < originalNumberRows; iRow++) weight[iRow] = 1.123e50; // Look at rows already in small problem int iSort; int numberDropped = 0; int numberKept = 0; int numberBinding = 0; int numberInfeasibilities = 0; double sumInfeasibilities = 0.0; for (iSort = 0; iSort < numberSort; iSort++) { iRow = sort[iSort]; //printf("%d %g %g\n",iRow,fullSolution[iRow],small.primalRowSolution()[iSort]); if (model2->getRowStatus(iRow) == ClpSimplex::basic) { // Basic - we can get rid of if early on if (iPass < takeOutPass && !dualInfeasible) { // may have hit max iterations so check double infeasibility = CoinMax(fullSolution[iRow] - rowUpper[iRow], rowLower[iRow] - fullSolution[iRow]); weight[iRow] = -infeasibility; if (infeasibility > 1.0e-8) { numberInfeasibilities++; sumInfeasibilities += infeasibility; } else { weight[iRow] = 1.0; numberDropped++; } } else { // keep weight[iRow] = -1.0e40; numberKept++; } } else { // keep weight[iRow] = -1.0e50; numberKept++; numberBinding++; } } // Now rest for (iRow = 0; iRow < originalNumberRows; iRow++) { sort[iRow] = iRow; if (weight[iRow] == 1.123e50) { // not looked at yet double infeasibility = CoinMax(fullSolution[iRow] - rowUpper[iRow], rowLower[iRow] - fullSolution[iRow]); weight[iRow] = -infeasibility; if (infeasibility > 1.0e-8) { numberInfeasibilities++; sumInfeasibilities += infeasibility; } } } // sort CoinSort_2(weight, weight + originalNumberRows, sort); numberSort = CoinMin(originalNumberRows, smallNumberRows + numberKept); memset(take, 0, originalNumberRows); for (iRow = 0; iRow < numberSort; iRow++) take[sort[iRow]] = 1; numberSmallColumns = 0; for (iColumn = 0; iColumn < numberColumns; iColumn++) { int n = 0; for (int j = start[iColumn]; j < start[iColumn] + length[iColumn]; j++) { int iRow = row[j]; if (take[iRow]) n++; } if (n) whichColumns[numberSmallColumns++] = iColumn; } printf("%d rows binding, %d rows kept, %d rows dropped - new size %d rows, %d columns\n", numberBinding, numberKept, numberDropped, numberSort, numberSmallColumns); printf("%d rows are infeasible - sum is %g\n", numberInfeasibilities, sumInfeasibilities); if (!numberInfeasibilities) { printf("Exiting as looks optimal\n"); break; } numberInfeasibilities = 0; sumInfeasibilities = 0.0; for (iSort = 0; iSort < numberSort; iSort++) { if (weight[iSort] > -1.0e30 && weight[iSort] < -1.0e-8) { numberInfeasibilities++; sumInfeasibilities += -weight[iSort]; } } printf("in small model %d rows are infeasible - sum is %g\n", numberInfeasibilities, sumInfeasibilities); } } delete [] weight; delete [] sort; delete [] whichColumns; delete [] take; // If problem is big you may wish to skip this model2->dual(); int numberBinding = 0; for (iRow = 0; iRow < originalNumberRows; iRow++) { if (model2->getRowStatus(iRow) != ClpSimplex::basic) numberBinding++; } printf("%d binding rows at end\n", numberBinding); pinfo.postsolve(true); int numberIterations = model2->numberIterations();; delete model2; /* After this postsolve model should be optimal. We can use checkSolution and test feasibility */ model.checkSolution(); if (model.numberDualInfeasibilities() || model.numberPrimalInfeasibilities()) printf("%g dual %g(%d) Primal %g(%d)\n", model.objectiveValue(), model.sumDualInfeasibilities(), model.numberDualInfeasibilities(), model.sumPrimalInfeasibilities(), model.numberPrimalInfeasibilities()); // But resolve for safety model.primal(1); numberIterations += model.numberIterations();; printf("Solve took %g seconds\n", CoinCpuTime() - time1); return 0; }
int main (int argc, const char *argv[]) { CbcSolver3 solver1; // Read in model using argv[1] // and assert that it is a clean model std::string mpsFileName; if (argc>=2) mpsFileName = argv[1]; int numMpsReadErrors = solver1.readMps(mpsFileName.c_str(),""); assert(numMpsReadErrors==0); double time1 = CoinCpuTime(); /* Options are: preprocess to do preprocessing time in minutes if 2 parameters and numeric taken as time */ bool preProcess=false; double minutes=-1.0; int nGoodParam=0; for (int iParam=2; iParam<argc;iParam++) { if (!strcmp(argv[iParam],"preprocess")) { preProcess=true; nGoodParam++; } else if (!strcmp(argv[iParam],"time")) { if (iParam+1<argc&&isdigit(argv[iParam+1][0])) { minutes=atof(argv[iParam+1]); if (minutes>=0.0) { nGoodParam+=2; iParam++; // skip time } } } } if (nGoodParam==0&&argc==3&&isdigit(argv[2][0])) { // If time is given then stop after that number of minutes minutes = atof(argv[2]); if (minutes>=0.0) nGoodParam=1; } if (nGoodParam!=argc-2) { printf("Usage <file> [preprocess] [time <minutes>] or <file> <minutes>\n"); exit(1); } solver1.initialSolve(); // Reduce printout solver1.setHintParam(OsiDoReducePrint,true,OsiHintTry); // Say we want scaling //solver1.setHintParam(OsiDoScale,true,OsiHintTry); //solver1.setCleanupScaling(1); // See if we want preprocessing OsiSolverInterface * solver2=&solver1; CglPreProcess process; if (preProcess) { /* Do not try and produce equality cliques and do up to 5 passes */ solver2 = process.preProcess(solver1,false,5); if (!solver2) { printf("Pre-processing says infeasible\n"); exit(2); } solver2->resolve(); } CbcModel model(*solver2); // Point to solver OsiSolverInterface * solver3 = model.solver(); CbcSolver3 * osiclp = dynamic_cast< CbcSolver3*> (solver3); assert (osiclp); const double fractionFix=0.985; osiclp->initialize(&model,NULL); osiclp->setAlgorithm(2); osiclp->setMemory(1000); osiclp->setNested(fractionFix); //osiclp->setNested(1.0); //off // Set up some cut generators and defaults // Probing first as gets tight bounds on continuous CglProbing generator1; generator1.setUsingObjective(true); generator1.setMaxPass(3); // Number of unsatisfied variables to look at generator1.setMaxProbe(10); // How far to follow the consequences generator1.setMaxLook(50); // Only look at rows with fewer than this number of elements generator1.setMaxElements(200); generator1.setRowCuts(3); CglGomory generator2; // try larger limit generator2.setLimit(300); CglKnapsackCover generator3; CglOddHole generator4; generator4.setMinimumViolation(0.005); generator4.setMinimumViolationPer(0.00002); // try larger limit generator4.setMaximumEntries(200); CglClique generator5; generator5.setStarCliqueReport(false); generator5.setRowCliqueReport(false); CglMixedIntegerRounding mixedGen; /* This is same as default constructor - (1,true,1) I presume if maxAggregate larger then slower but maybe better criterion can be 1 through 3 Reference: Hugues Marchand and Laurence A. Wolsey Aggregation and Mixed Integer Rounding to Solve MIPs Operations Research, 49(3), May-June 2001. */ int maxAggregate=1; bool multiply=true; int criterion=1; CglMixedIntegerRounding2 mixedGen2(maxAggregate,multiply,criterion); CglFlowCover flowGen; // Add in generators // Experiment with -1 and -99 etc model.addCutGenerator(&generator1,-99,"Probing"); //model.addCutGenerator(&generator2,-1,"Gomory"); //model.addCutGenerator(&generator3,-1,"Knapsack"); //model.addCutGenerator(&generator4,-1,"OddHole"); //model.addCutGenerator(&generator5,-1,"Clique"); //model.addCutGenerator(&flowGen,-1,"FlowCover"); //model.addCutGenerator(&mixedGen,-1,"MixedIntegerRounding"); //model.addCutGenerator(&mixedGen2,-1,"MixedIntegerRounding2"); // Say we want timings int numberGenerators = model.numberCutGenerators(); int iGenerator; for (iGenerator=0;iGenerator<numberGenerators;iGenerator++) { CbcCutGenerator * generator = model.cutGenerator(iGenerator); generator->setTiming(true); } // Allow rounding heuristic CbcRounding heuristic1(model); model.addHeuristic(&heuristic1); // And Greedy heuristic CbcHeuristicGreedyCover heuristic2(model); // Use original upper and perturb more heuristic2.setAlgorithm(11); model.addHeuristic(&heuristic2); // Redundant definition of default branching (as Default == User) CbcBranchUserDecision branch; model.setBranchingMethod(&branch); // Definition of node choice CbcCompareUser compare; model.setNodeComparison(compare); int iColumn; int numberColumns = solver3->getNumCols(); // do pseudo costs CbcObject ** objects = new CbcObject * [numberColumns+1]; const CoinPackedMatrix * matrix = solver3->getMatrixByCol(); // Column copy const int * columnLength = matrix->getVectorLengths(); const double * objective = model.getObjCoefficients(); int n=0; for (iColumn=0;iColumn<numberColumns;iColumn++) { if (solver3->isInteger(iColumn)) { double costPer = objective[iColumn]/ ((double) columnLength[iColumn]); CbcSimpleIntegerPseudoCost * newObject = new CbcSimpleIntegerPseudoCost(&model,n,iColumn, costPer,costPer); newObject->setMethod(3); objects[n++]= newObject; } } // and special fix lots branch objects[n++]=new CbcBranchToFixLots(&model,-1.0e-6,fractionFix+0.01,1,0,NULL); model.addObjects(n,objects); for (iColumn=0;iColumn<n;iColumn++) delete objects[iColumn]; delete [] objects; // High priority for odd object int followPriority=1; model.passInPriorities(&followPriority,true); // Do initial solve to continuous model.initialSolve(); // Could tune more model.setMinimumDrop(CoinMin(1.0, fabs(model.getMinimizationObjValue())*1.0e-3+1.0e-4)); if (model.getNumCols()<500) model.setMaximumCutPassesAtRoot(-100); // always do 100 if possible else if (model.getNumCols()<5000) model.setMaximumCutPassesAtRoot(100); // use minimum drop else model.setMaximumCutPassesAtRoot(20); //model.setMaximumCutPasses(1); // Do more strong branching if small //if (model.getNumCols()<5000) //model.setNumberStrong(10); // Switch off strong branching if wanted model.setNumberStrong(0); model.solver()->setIntParam(OsiMaxNumIterationHotStart,100); // If time is given then stop after that number of minutes if (minutes>=0.0) { std::cout<<"Stopping after "<<minutes<<" minutes"<<std::endl; model.setDblParam(CbcModel::CbcMaximumSeconds,60.0*minutes); } // Switch off most output if (model.getNumCols()<300000) { model.messageHandler()->setLogLevel(1); //model.solver()->messageHandler()->setLogLevel(0); } else { model.messageHandler()->setLogLevel(2); model.solver()->messageHandler()->setLogLevel(1); } //model.messageHandler()->setLogLevel(2); //model.solver()->messageHandler()->setLogLevel(2); //model.setPrintFrequency(50); #define DEBUG_CUTS #ifdef DEBUG_CUTS // Set up debugger by name (only if no preprocesing) if (!preProcess) { std::string problemName ; //model.solver()->getStrParam(OsiProbName,problemName) ; //model.solver()->activateRowCutDebugger(problemName.c_str()) ; model.solver()->activateRowCutDebugger("cap6000a") ; } #endif // Do complete search try { model.branchAndBound(); } catch (CoinError e) { e.print(); if (e.lineNumber()>=0) std::cout<<"This was from a CoinAssert"<<std::endl; exit(0); } //void printHowMany(); //printHowMany(); std::cout<<mpsFileName<<" took "<<CoinCpuTime()-time1<<" seconds, " <<model.getNodeCount()<<" nodes with objective " <<model.getObjValue() <<(!model.status() ? " Finished" : " Not finished") <<std::endl; // Print more statistics std::cout<<"Cuts at root node changed objective from "<<model.getContinuousObjective() <<" to "<<model.rootObjectiveAfterCuts()<<std::endl; for (iGenerator=0;iGenerator<numberGenerators;iGenerator++) { CbcCutGenerator * generator = model.cutGenerator(iGenerator); std::cout<<generator->cutGeneratorName()<<" was tried " <<generator->numberTimesEntered()<<" times and created " <<generator->numberCutsInTotal()<<" cuts of which " <<generator->numberCutsActive()<<" were active after adding rounds of cuts"; if (generator->timing()) std::cout<<" ( "<<generator->timeInCutGenerator()<<" seconds)"<<std::endl; else std::cout<<std::endl; } // Print solution if finished - we can't get names from Osi! if (model.getMinimizationObjValue()<1.0e50) { // post process if (preProcess) process.postProcess(*model.solver()); int numberColumns = model.solver()->getNumCols(); const double * solution = model.solver()->getColSolution(); int iColumn; std::cout<<std::setiosflags(std::ios::fixed|std::ios::showpoint)<<std::setw(14); std::cout<<"--------------------------------------"<<std::endl; for (iColumn=0;iColumn<numberColumns;iColumn++) { double value=solution[iColumn]; if (fabs(value)>1.0e-7&&model.solver()->isInteger(iColumn)) std::cout<<std::setw(6)<<iColumn<<" "<<value<<std::endl; } std::cout<<"--------------------------------------"<<std::endl; std::cout<<std::resetiosflags(std::ios::fixed|std::ios::showpoint|std::ios::scientific); } return 0; }
bool calModel::search (CalCubeHeur &calCube, FILE *f, int repl) { int N = instance_ -> N (), n = instance_ -> n (), n_iter = (calInstance::GLOBAL == instance_ -> algType ()) ? 1 : instance_ -> nSolves (); double *bestSol = new double [1 + 2*N], bestObj = COIN_DBL_MAX; double *s0 = NULL; for (int nRetries = 0; !GLOBAL_interrupt && (nRetries < n_iter) && (square (bestObj) > instance_ -> eps ()); ++nRetries) { setMaximumSeconds (CoinMin (instance_ -> maxTime () < 0. ? COIN_DBL_MAX : instance_ -> maxTime (), instance_ -> maxTotalTime () < 0. ? COIN_DBL_MAX : (instance_ -> maxTotalTime () - CoinCpuTime ()) / (instance_ -> nReplications () - repl))); calModel *b = clone (); OsiSolverInterface *si = b -> solver (); for (int i=0; i<N; ++i) { si -> setColLower (1 + N + i, 0.); si -> setColUpper (1 + N + i, 1.); } if (calInstance::GLOBAL == instance_ -> algType ()) { // do nothing: just run the BB } else if (0 == nRetries) { // // First step: generate initial solution, either from input // vector or through the Cube variant // // Generate initial point ON SUBSPACE. Does nothing if algtype // in {RANDOM, GLOBAL} // s0 = calCube. generateInitS (*si); calCube. standalone (s0); // call Cube method b -> changeLU (*si, s0); // fixes some of the s variables after // cube's flight phase } else { // change LU bounds based on current solution #ifdef DEBUG printVec (s0, N, "s0"); #endif const double // reduce changes when random and solution available fraction = FRACTION * (((calInstance::RANDOM == instance_ -> algType ()) && (instance_ -> d () [0] >= 0.)) ? RANDOM_MOBILITY : 1.), multiplier = fraction * (double) (N_RESTART - (nRetries % N_RESTART)) / N_RESTART, threshold_0 = multiplier * (double) (N-n) / N, // free half 0-fixed at beginning threshold_1 = multiplier * (double) n / N; // free half 1-fixed //threshold_0 = CoinMax (1. / CoinMax (1., (double) (N-n)), multiplier * (double) (N-n) / N), // free half 0-fixed at beginning //threshold_1 = CoinMax (1. / CoinMax (1., (double) n), multiplier * (double) n / N); // free half 1-fixed bool one_changed = false; for (int nAttempts = 0; nAttempts < 20 && !one_changed; ++nAttempts) for (int i=0; i<N; ++i) if (s0 [i] < 1e-5) {if (drand48 () > threshold_0) si -> setColUpper (1 + N + i, 0.); else one_changed = true;} else if (s0 [i] > 1 - 1e-5) {if (drand48 () > threshold_1) si -> setColLower (1 + N + i, 1.); else one_changed = true;} #ifdef DEBUG char filename [40]; sprintf (filename, "lp_%d_%d", repl, nRetries); si -> writeLp (filename); #endif // int nChanges = CoinMax (1, n / nRetries); // <------------------ Number of changed variables // for (int i=0; i<nChanges;) { // int indChange = floor ((N - 1e-4) * drand48 ()); // printf ("trying %d [%g,%g], i=%d\n", indChange, lb [1 + N + indChange], ub [1 + N + indChange], i); // if (ub [1 + N + indChange] < 1e-5) {si -> setColUpper (1 + N + indChange, 1.); ++i;} // if (lb [1 + N + indChange] > 1 - 1e-5) {si -> setColLower (1 + N + indChange, 0.); ++i;} // } } GLOBAL_curBB = b; // /| // / |--------+ b -> branchAndBound (); // < | | // \ |--------+ // \| //assert (fabs (b -> bestObj () - val [0]) < 1e-5); printf ("BB iteration %4d done (%10.2fs). ", 1+nRetries, CoinCpuTime ()); //optimal = b -> isProvenOptimal(); //const double *val = b -> getColSolution(); //int numberColumns = model.getNumCols(); if (b -> bestObj () < 1e20) printf ("Best solution: value %10.4f\n", square (b -> bestObj ())); else printf ("No solution found :-(\n"); if (b -> bestSol ()) { if (b -> bestObj () < bestObj) { bestObj = b -> bestObj (); CoinCopyN (b -> bestSol (), 2*N+1, bestSol); } if (!s0) s0 = new double [N]; CoinCopyN (b -> bestSol () + 1 + N, N, s0); } delete b; } bool retval = true, row_format = (calInstance::ROW_BASED == instance_ -> outFormat ()); delete [] s0; double w0 = (double) N / instance_ -> n (); if (bestObj < 1e20) { const double *val = bestSol; if (row_format) fprintf (f, "%lf,", square (bestObj)); //double *d = instance_ -> d (); printf ("sample:\n"); for (int j=N+1, np=0; j<=2*N; ++j) { char strNum [5]; sprintf (strNum, "%d", j-N); if (!row_format) fprintf (f, "%d,%g,%s,%d,%g,\n", 1+repl, square (bestObj), instance_ -> id (j-N-1) ? instance_ -> id (j-N-1) : strNum, (fabs (val [j]) > 1e-6) ? 1 : 0, w0 + val [j-N]); if (fabs (val [j]) > 1e-6) { if (row_format) fprintf (f, "1,"); printf ("%d ", j-N); if (!(++np % 10)) printf ("\n"); } else if (row_format) fprintf (f, "0,"); } printf ("\nweights:\n"); for (int j=1, np=0; j<=N; ++j) { if (row_format) fprintf (f, "%g,", w0 + val [j]); if (fabs (val [j]) > 1e-6) { printf ("[%d,%g] ", j, w0 + val [j]); if (!(++np % 10)) printf ("\n"); } } if (square (bestObj) > instance_ -> eps ()) { printf ("(warning: solution has large objective at replication %d)", 1 + repl); //retval = false; } printf ("\n"); if (row_format) fprintf (f, "\n"); fflush (f); } delete [] bestSol; return retval; }
int main (int argc, const char *argv[]) { // Empty model ClpSimplex model; std::string mpsFileName = "../../Data/Netlib/25fv47.mps"; if (argc >= 2) mpsFileName = argv[1]; int status = model.readMps(mpsFileName.c_str(), true); if (status) { fprintf(stderr, "Bad readMps %s\n", mpsFileName.c_str()); fprintf(stdout, "Bad readMps %s\n", mpsFileName.c_str()); exit(1); } // Point to data int numberRows = model.numberRows(); const double * rowLower = model.rowLower(); const double * rowUpper = model.rowUpper(); int numberColumns = model.numberColumns(); const double * columnLower = model.columnLower(); const double * columnUpper = model.columnUpper(); const double * columnObjective = model.objective(); CoinPackedMatrix * matrix = model.matrix(); // get row copy CoinPackedMatrix rowCopy = *matrix; rowCopy.reverseOrdering(); const int * column = rowCopy.getIndices(); const int * rowLength = rowCopy.getVectorLengths(); const CoinBigIndex * rowStart = rowCopy.getVectorStarts(); const double * element = rowCopy.getElements(); //const int * row = matrix->getIndices(); //const int * columnLength = matrix->getVectorLengths(); //const CoinBigIndex * columnStart = matrix->getVectorStarts(); //const double * elementByColumn = matrix->getElements(); // solve model.dual(); // Now build new model CoinModel build; double time1 = CoinCpuTime(); // Row bounds int iRow; for (iRow = 0; iRow < numberRows; iRow++) { build.setRowBounds(iRow, rowLower[iRow], rowUpper[iRow]); // optional name build.setRowName(iRow, model.rowName(iRow).c_str()); } // Column bounds and objective int iColumn; for (iColumn = 0; iColumn < numberColumns; iColumn++) { build.setColumnLower(iColumn, columnLower[iColumn]); build.setColumnUpper(iColumn, columnUpper[iColumn]); build.setObjective(iColumn, columnObjective[iColumn]); // optional name build.setColumnName(iColumn, model.columnName(iColumn).c_str()); } // Adds elements one by one by row (backwards by row) for (iRow = numberRows - 1; iRow >= 0; iRow--) { int start = rowStart[iRow]; for (int j = start; j < start + rowLength[iRow]; j++) build(iRow, column[j], element[j]); } double time2 = CoinCpuTime(); // Now create clpsimplex ClpSimplex model2; model2.loadProblem(build); double time3 = CoinCpuTime(); printf("Time for build using CoinModel is %g (%g for loadproblem)\n", time3 - time1, time3 - time2); model2.dual(); // Now do with strings attached // Save build to show how to go over rows CoinModel saveBuild = build; build = CoinModel(); time1 = CoinCpuTime(); // Column bounds for (iColumn = 0; iColumn < numberColumns; iColumn++) { build.setColumnLower(iColumn, columnLower[iColumn]); build.setColumnUpper(iColumn, columnUpper[iColumn]); } // Objective - half the columns as is and half with multiplier of "1.0+multiplier" // Pick up from saveBuild (for no reason at all) for (iColumn = 0; iColumn < numberColumns; iColumn++) { double value = saveBuild.objective(iColumn); if (iColumn * 2 < numberColumns) { build.setObjective(iColumn, columnObjective[iColumn]); } else { // create as string char temp[100]; sprintf(temp, "%g + abs(%g*multiplier)", value, value); build.setObjective(iColumn, temp); } } // It then adds rows one by one but for half the rows sets their values // with multiplier of "1.0+1.5*multiplier" for (iRow = 0; iRow < numberRows; iRow++) { if (iRow * 2 < numberRows) { // add row in simple way int start = rowStart[iRow]; build.addRow(rowLength[iRow], column + start, element + start, rowLower[iRow], rowUpper[iRow]); } else { // As we have to add one by one let's get from saveBuild CoinModelLink triple = saveBuild.firstInRow(iRow); while (triple.column() >= 0) { int iColumn = triple.column(); if (iColumn * 2 < numberColumns) { // just value as normal build(iRow, triple.column(), triple.value()); } else { // create as string char temp[100]; sprintf(temp, "%g + (1.5*%g*multiplier)", triple.value(), triple.value()); build(iRow, iColumn, temp); } triple = saveBuild.next(triple); } // but remember to do rhs build.setRowLower(iRow, rowLower[iRow]); build.setRowUpper(iRow, rowUpper[iRow]); } } time2 = CoinCpuTime(); // Now create ClpSimplex // If small switch on error printing if (numberColumns < 50) build.setLogLevel(1); int numberErrors = model2.loadProblem(build); // should fail as we never set multiplier assert (numberErrors); time3 = CoinCpuTime() - time2; // subtract out unsuccessful times time1 += time3; time2 += time3; build.associateElement("multiplier", 0.0); numberErrors = model2.loadProblem(build); assert (!numberErrors); time3 = CoinCpuTime(); printf("Time for build using CoinModel is %g (%g for successful loadproblem)\n", time3 - time1, time3 - time2); build.writeMps("zero.mps"); // It then loops with multiplier going from 0.0 to 2.0 in increments of 0.1 for (double multiplier = 0.0; multiplier < 2.0; multiplier += 0.1) { build.associateElement("multiplier", multiplier); numberErrors = model2.loadProblem(build, true); assert (!numberErrors); model2.dual(); } return 0; }
void CouenneCutGenerator::generateCuts (const OsiSolverInterface &si, OsiCuts &cs, const CglTreeInfo info) #if CGL_VERSION_MAJOR == 0 && CGL_VERSION_MINOR <= 57 const #endif { // check if out of time or if an infeasibility cut (iis of type 0) // was added as a result of, e.g., pruning on BT. If so, no need to // run this. if (isWiped (cs) || (CoinCpuTime () > problem_ -> getMaxCpuTime ())) return; #ifdef FM_TRACE_OPTSOL double currCutOff = problem_->getCutOff(); double bestVal = 1e50; CouenneRecordBestSol *rs = problem_->getRecordBestSol(); if(rs->getHasSol()) { bestVal = rs->getVal(); } if(currCutOff > bestVal) { //problem_ -> setCutOff (bestVal - 1e-6); // FIXME: don't add numerical constants problem_ -> setCutOff (bestVal); int indObj = problem_->Obj(0)->Body()->Index(); if (indObj >= 0) { OsiColCut *objCut = new OsiColCut; objCut->setUbs(1, &indObj, &bestVal); cs.insert(objCut); delete objCut; } } #endif #ifdef FM_PRINT_INFO if((BabPtr_ != NULL) && (info.level >= 0) && (info.pass == 0) && (BabPtr_->model().getNodeCount() > lastPrintLine)) { printLineInfo(); lastPrintLine += 1; } #endif const int infeasible = 1; int nInitCuts = cs.sizeRowCuts (); CouNumber *&realOpt = problem_ -> bestSol (), *saveOptimum = realOpt; if (!firstcall_ && realOpt) { // have a debug optimal solution. Check if current bounds // contain it, otherwise pretend it does not exist CouNumber *opt = realOpt; const CouNumber *sol = si.getColSolution (), *lb = si.getColLower (), *ub = si.getColUpper (); int objind = problem_ -> Obj (0) -> Body () -> Index (); for (int j=0, i=problem_ -> nVars (); i--; j++, opt++, lb++, ub++) if ((j != objind) && ((*opt < *lb - COUENNE_EPS * (1 + CoinMin (fabs (*opt), fabs (*lb)))) || (*opt > *ub + COUENNE_EPS * (1 + CoinMin (fabs (*opt), fabs (*ub)))))) { jnlst_ -> Printf (J_VECTOR, J_CONVEXIFYING, "out of bounds, ignore x%d = %g [%g,%g] opt = %g\n", problem_ -> nVars () - i - 1, *sol, *lb, *ub, *opt); // optimal point is not in current bounding box, // pretend realOpt is NULL until we return from this procedure realOpt = NULL; break; } } /*static int count = 0; char fname [20]; sprintf (fname, "relax_%d", count++); si.writeLp (fname); printf ("writing %s\n", fname);*/ jnlst_ -> Printf (J_DETAILED, J_CONVEXIFYING, "generateCuts: level = %d, pass = %d, intree = %d\n", info.level, info.pass, info.inTree); Bonmin::BabInfo * babInfo = dynamic_cast <Bonmin::BabInfo *> (si.getAuxiliaryInfo ()); if (babInfo) babInfo -> setFeasibleNode (); double now = CoinCpuTime (); int ncols = problem_ -> nVars (); // This vector contains variables whose bounds have changed due to // branching, reduced cost fixing, or bound tightening below. To be // used with malloc/realloc/free t_chg_bounds *chg_bds = new t_chg_bounds [ncols]; /*for (int i=0; i < ncols; i++) if (problem_ -> Var (i) -> Multiplicity () <= 0) { chg_bds [i].setLower (t_chg_bounds::UNCHANGED); chg_bds [i].setUpper (t_chg_bounds::UNCHANGED); }*/ problem_ -> installCutOff (); // install upper bound if (firstcall_) { // First convexification ////////////////////////////////////// // OsiSolverInterface is empty yet, no information can be obtained // on variables or bounds -- and none is needed since our // constructor populated *problem_ with variables and bounds. We // only need to update the auxiliary variables and bounds with // their current value. for (int i=0; i < ncols; i++) if (problem_ -> Var (i) -> Multiplicity () > 0) { chg_bds [i].setLower (t_chg_bounds::CHANGED); chg_bds [i].setUpper (t_chg_bounds::CHANGED); } // start with FBBT, should take advantage of cutoff found by NLP // run AFTER initial FBBT... if (problem_ -> doFBBT () && (! (problem_ -> boundTightening (chg_bds, babInfo)))) jnlst_ -> Printf (J_STRONGWARNING, J_CONVEXIFYING, "Couenne: WARNING, first convexification is infeasible\n"); // For each auxiliary variable replacing the original (nonlinear) // constraints, check if corresponding bounds are violated, and // add cut to cs int nnlc = problem_ -> nCons (); for (int i=0; i<nnlc; i++) { if (CoinCpuTime () > problem_ -> getMaxCpuTime ()) break; // for each constraint CouenneConstraint *con = problem_ -> Con (i); // (which has an aux as its body) int objindex = con -> Body () -> Index (); if ((objindex >= 0) && ((con -> Body () -> Type () == AUX) || (con -> Body () -> Type () == VAR))) { // get the auxiliary that is at the lhs exprVar *conaux = problem_ -> Var (objindex); if (conaux && (conaux -> Type () == AUX) && (conaux -> Image ()) && (conaux -> Image () -> Linearity () <= LINEAR)) { // reduce density of problem by adding w >= l rather than // ax + b >= l for any linear auxiliary defined as w := ax+b double lb = (*(con -> Lb ())) (), ub = (*(con -> Ub ())) (); OsiColCut newBound; if (lb > -COUENNE_INFINITY) newBound.setLbs (1, &objindex, &lb); if (ub < COUENNE_INFINITY) newBound.setUbs (1, &objindex, &ub); cs.insert (newBound); // the auxiliary w of constraint w <= b is associated with a // linear expression w = ax: add constraint ax <= b /*conaux -> Image () -> generateCuts (conaux, si, cs, this, chg_bds, conaux -> Index (), (*(con -> Lb ())) (), (*(con -> Ub ())) ());*/ // take it from the list of the variables to be linearized // // DO NOT decrease multiplicity. Even if it is a linear // term, its bounds can still be used in implied bounds // // Are we sure? That will happen only if its multiplicity is // nonzero, for otherwise this aux is only used here, and is // useless elsewhere // //conaux -> decreaseMult (); // !!! } // also, add constraint w <= b // not now, do it later // // if there exists violation, add constraint // CouNumber l = con -> Lb () -> Value (), // u = con -> Ub () -> Value (); // // tighten bounds in Couenne's problem representation // problem_ -> Lb (index) = CoinMax (l, problem_ -> Lb (index)); // problem_ -> Ub (index) = CoinMin (u, problem_ -> Ub (index)); } else { // body is more than just a variable, but it should be // linear. If so, generate equivalent linear cut assert (false); // TODO } } if (jnlst_ -> ProduceOutput (J_ITERSUMMARY, J_CONVEXIFYING)) { if (cs.sizeRowCuts ()) { jnlst_ -> Printf (J_ITERSUMMARY, J_CONVEXIFYING,"Couenne: %d constraint row cuts\n", cs.sizeRowCuts ()); for (int i=0; i<cs.sizeRowCuts (); i++) cs.rowCutPtr (i) -> print (); } if (cs.sizeColCuts ()) { jnlst_ -> Printf (J_ITERSUMMARY, J_CONVEXIFYING,"Couenne: %d constraint col cuts\n", cs.sizeColCuts ()); for (int i=0; i<cs.sizeColCuts (); i++) cs.colCutPtr (i) -> print (); } } } else { // use new optimum as lower bound for variable associated w/objective int indobj = problem_ -> Obj (0) -> Body () -> Index (); // transmit solution from OsiSolverInterface to problem problem_ -> domain () -> push (&si, &cs); if (indobj >= 0) { // Use current value of objvalue's x as a lower bound for bound // tightening double lp_bound = problem_ -> domain () -> x (indobj); //if (problem_ -> Obj (0) -> Sense () == MINIMIZE) {if (lp_bound > problem_ -> Lb (indobj)) problem_ -> Lb (indobj) = lp_bound;} //else {if (lp_bound < problem_ -> Ub (indobj)) problem_ -> Ub (indobj) = lp_bound;} } updateBranchInfo (si, problem_, chg_bds, info); // info.depth >= 0 || info.pass >= 0 } // restore constraint bounds before tightening and cut generation for (int i = problem_ -> nCons (); i--;) { // for each constraint CouenneConstraint *con = problem_ -> Con (i); // (which has an aux as its body) int objindex = con -> Body () -> Index (); if ((objindex >= 0) && ((con -> Body () -> Type () == AUX) || (con -> Body () -> Type () == VAR))) { // if there exists violation, add constraint CouNumber l = con -> Lb () -> Value (), u = con -> Ub () -> Value (); // tighten bounds in Couenne's problem representation problem_ -> Lb (objindex) = CoinMax (l, problem_ -> Lb (objindex)); problem_ -> Ub (objindex) = CoinMin (u, problem_ -> Ub (objindex)); } } problem_ -> installCutOff (); // install upper bound fictitiousBound (cs, problem_, false); // install finite lower bound, if currently -inf int *changed = NULL, nchanged; // Bound tightening /////////////////////////////////////////// // do bound tightening only at first pass of cutting plane in a node // of BB tree (info.pass == 0) or if first call (creation of RLT, // info.pass == -1) try { // Before bound tightening, compute symmetry group. After bound // tightening is done, we can apply further tightening using orbit // information. #ifdef COIN_HAS_NTY // ChangeBounds (psi -> getColLower (), // psi -> getColUpper (), // psi -> getNumCols ()); if (problem_ -> orbitalBranching ()) problem_ -> Compute_Symmetry (); #endif // Bound tightening //////////////////////////////////// /*printf ("== BT ================\n"); for (int i = 0; i < problem_ -> nVars (); i++) if (problem_ -> Var (i) -> Multiplicity () > 0) printf ("%4d %+20.8g [%+20.8g,%+20.8g]\n", i, problem_ -> X (i), problem_ -> Lb (i), problem_ -> Ub (i)); printf("=============================\n");*/ // Reduced Cost BT -- to be done first to use rcost correctly if (!firstcall_ && // have a linearization already problem_ -> doRCBT () && // authorized to do reduced cost tightening problem_ -> redCostBT (&si, chg_bds) && // some variables were tightened with reduced cost !(problem_ -> btCore (chg_bds))) // in this case, do another round of FBBT throw infeasible; // FBBT if (problem_ -> doFBBT () && //(info.pass <= 0) && // do it in subsequent rounds too (! (problem_ -> boundTightening (chg_bds, babInfo)))) throw infeasible; // OBBT if (!firstcall_ && // no obbt if first call (there is no LP to work with) problem_ -> obbt (this, si, cs, info, babInfo, chg_bds) < 0) throw infeasible; // Bound tightening done ///////////////////////////// if ((problem_ -> doFBBT () || problem_ -> doOBBT () || problem_ -> doABT ()) && (jnlst_ -> ProduceOutput (J_VECTOR, J_CONVEXIFYING))) { jnlst_ -> Printf(J_VECTOR, J_CONVEXIFYING,"== after bt =============\n"); for (int i = 0; i < problem_ -> nVars (); i++) if (problem_ -> Var (i) -> Multiplicity () > 0) jnlst_->Printf(J_VECTOR, J_CONVEXIFYING,"%4d %+20.8g [%+20.8g,%+20.8g]\n", i, problem_ -> X (i), problem_ -> Lb (i), problem_ -> Ub (i)); jnlst_->Printf(J_VECTOR, J_CONVEXIFYING,"=============================\n"); } // Use orbit info to tighten bounds #ifdef COIN_HAS_NTY // TODO: when independent bound tightener, can get original bounds // through si.getCol{Low,Upp}er() if (problem_ -> orbitalBranching () && !firstcall_) { CouNumber *lb = problem_ -> Lb (), *ub = problem_ -> Ub (); std::vector<std::vector<int> > *new_orbits = problem_ -> getNtyInfo () -> getOrbits(); for (int i=0, ii = problem_ -> getNtyInfo () -> getNumOrbits (); ii--; i++){ CouNumber ll = -COUENNE_INFINITY, uu = COUENNE_INFINITY; std::vector <int> orbit = (*new_orbits)[i]; if (orbit.size () <= 1) continue; // not much to do when only one variable in this orbit if (jnlst_ -> ProduceOutput (J_VECTOR, J_BOUNDTIGHTENING)) { printf ("orbit bounds: "); fflush (stdout); for(int j = 0; j < orbit.size (); j++) { printf ("x_%d [%g,%g] ", orbit[j], lb [orbit [j]], ub [orbit [j]]); fflush (stdout); } printf ("\n"); } for (int j = 0; j < orbit.size (); j++) { int indOrb = orbit [j]; if (indOrb < problem_ -> nVars ()) { if (lb [indOrb] > ll) ll = lb [indOrb]; if (ub [indOrb] < uu) uu = ub [indOrb]; } } jnlst_ -> Printf (J_VECTOR, J_BOUNDTIGHTENING, " --> new common lower bounds: [%g,--]\n", ll); for(int j = 0; j < orbit.size (); j++) { int indOrb = orbit [j]; if (indOrb < problem_ -> nVars ()){ lb [indOrb] = ll; ub [indOrb] = uu; } } } delete new_orbits; } #endif // Generate convexification cuts ////////////////////////////// sparse2dense (ncols, chg_bds, changed, nchanged); double *nlpSol = NULL; //-------------------------------------------- if (true) { if (babInfo) nlpSol = const_cast <double *> (babInfo -> nlpSolution ()); // Aggressive Bound Tightening //////////////////////////////// int logAbtLev = problem_ -> logAbtLev (); if (problem_ -> doABT () && // flag is checked, AND ((logAbtLev != 0) || // (parameter is nonzero OR (info.level == 0)) && // we are at root node), AND (info.pass == 0) && // at first round of cuts, AND ((logAbtLev < 0) || // (logAbtLev = -1, OR (info.level <= logAbtLev) || // depth is lower than COU_OBBT_CUTOFF_LEVEL, OR (CoinDrand48 () < // probability inversely proportional to the level) pow (2., (double) logAbtLev - (info.level + 1))))) { jnlst_ -> Printf(J_VECTOR, J_BOUNDTIGHTENING," performing ABT\n"); if (! (problem_ -> aggressiveBT (nlp_, chg_bds, info, babInfo))) throw infeasible; sparse2dense (ncols, chg_bds, changed, nchanged); } // obtain solution just found by nlp solver // Auxiliaries should be correct. solution should be the one found // at the node even if not as good as the best known. // save violation flag and disregard it while adding cut at NLP // point (which are not violated by the current, NLP, solution) bool save_av = addviolated_; addviolated_ = false; // save values problem_ -> domain () -> push (problem_ -> nVars (), problem_ -> domain () -> x (), problem_ -> domain () -> lb (), problem_ -> domain () -> ub (), false); // fill originals with nlp values if (nlpSol) { CoinCopyN (nlpSol, problem_ -> nOrigVars (), problem_ -> domain () -> x ()); //problem_ -> initAuxs (); problem_ -> getAuxs (problem_ -> domain () -> x ()); } if (jnlst_ -> ProduceOutput (J_VECTOR, J_CONVEXIFYING)) { jnlst_ -> Printf(J_VECTOR, J_CONVEXIFYING,"== genrowcuts on NLP =============\n"); for (int i = 0; i < problem_ -> nVars (); i++) if (problem_ -> Var (i) -> Multiplicity () > 0) jnlst_->Printf(J_VECTOR, J_CONVEXIFYING,"%4d %+20.8g [%+20.8g,%+20.8g]\n", i, problem_ -> X (i), problem_ -> Lb (i), problem_ -> Ub (i)); jnlst_->Printf(J_VECTOR, J_CONVEXIFYING,"=============================\n"); } problem_ -> domain () -> current () -> isNlp () = true; genRowCuts (si, cs, nchanged, changed, chg_bds); // add cuts problem_ -> domain () -> pop (); // restore point addviolated_ = save_av; // restore previous value // if (!firstcall_) // keep solution if called from extractLinearRelaxation() if (babInfo) babInfo -> setHasNlpSolution (false); // reset it after use //AW HERE } else { if (jnlst_ -> ProduceOutput (J_VECTOR, J_CONVEXIFYING)) { jnlst_ -> Printf(J_VECTOR, J_CONVEXIFYING,"== genrowcuts on LP =============\n"); for (int i = 0; i < problem_ -> nVars (); i++) if (problem_ -> Var (i) -> Multiplicity () > 0) jnlst_->Printf(J_VECTOR, J_CONVEXIFYING,"%4d %+20.8g [%+20.8g,%+20.8g]\n", i, problem_ -> X (i), problem_ -> Lb (i), problem_ -> Ub (i)); jnlst_->Printf(J_VECTOR, J_CONVEXIFYING,"=============================\n"); } genRowCuts (si, cs, nchanged, changed, chg_bds); } // change tightened bounds through OsiCuts if (nchanged) genColCuts (si, cs, nchanged, changed); if (firstcall_ && (cs.sizeRowCuts () >= 1)) jnlst_->Printf(J_ITERSUMMARY, J_CONVEXIFYING, "Couenne: %d initial row cuts\n", cs.sizeRowCuts ()); if (realOpt && // this is a good time to check if we have cut the optimal solution isOptimumCut (realOpt, cs, problem_)) jnlst_->Printf(J_ITERSUMMARY, J_CONVEXIFYING, "Warning: Optimal solution was cut\n"); } catch (int exception) { if ((exception == infeasible) && (!firstcall_)) { jnlst_ -> Printf (J_ITERSUMMARY, J_CONVEXIFYING, "Couenne: Infeasible node\n"); WipeMakeInfeas (cs); } if (babInfo) // set infeasibility to true in order to skip NLP heuristic babInfo -> setInfeasibleNode (); } delete [] chg_bds; if (changed) free (changed); if (firstcall_) { jnlst_ -> Printf (J_SUMMARY, J_CONVEXIFYING, "Couenne: %d cuts (%d row, %d col) for linearization\n", cs.sizeRowCuts () + cs.sizeColCuts (), cs.sizeRowCuts (), cs.sizeColCuts ()); fictitiousBound (cs, problem_, true); firstcall_ = false; ntotalcuts_ = nrootcuts_ = cs.sizeRowCuts (); } else { problem_ -> domain () -> pop (); ntotalcuts_ += (cs.sizeRowCuts () - nInitCuts); if (saveOptimum) realOpt = saveOptimum; // restore debug optimum } septime_ += CoinCpuTime () - now; if (jnlst_ -> ProduceOutput (J_ITERSUMMARY, J_CONVEXIFYING)) { if (cs.sizeColCuts ()) { jnlst_ -> Printf (J_ITERSUMMARY, J_CONVEXIFYING,"Couenne col cuts:\n"); for (int i=0; i<cs.sizeColCuts (); i++) cs.colCutPtr (i) -> print (); } } if (!(info.inTree)) rootTime_ = CoinCpuTime (); }
/* 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; }
const CoinPresolveAction *subst_constraint_action::presolve ( CoinPresolveMatrix *prob, const int *implied_free, const int *whichFree, int numberFree, const CoinPresolveAction *next, int maxLook) { # if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0 # if PRESOLVE_DEBUG > 0 std::cout << "Entering subst_constraint_action::presolve, fill level " << maxLook << ", " << numberFree << " candidates." << std::endl ; # endif presolve_consistent(prob) ; presolve_links_ok(prob) ; presolve_check_sol(prob) ; presolve_check_nbasic(prob) ; # endif # if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING > 0 int startEmptyRows = 0 ; int startEmptyColumns = 0 ; startEmptyRows = prob->countEmptyRows() ; startEmptyColumns = prob->countEmptyCols() ; # if COIN_PRESOLVE_TUNING > 0 double startTime = 0.0 ; if (prob->tuning_) startTime = CoinCpuTime() ; # endif # endif /* Unpack the row- and column-major representations. */ const int ncols = prob->ncols_ ; const int nrows = prob->nrows_ ; CoinBigIndex *rowStarts = prob->mrstrt_ ; int *rowLengths = prob->hinrow_ ; double *rowCoeffs = prob->rowels_ ; int *colIndices = prob->hcol_ ; presolvehlink *rlink = prob->rlink_ ; CoinBigIndex *colStarts = prob->mcstrt_ ; int *colLengths = prob->hincol_ ; double *colCoeffs = prob->colels_ ; int *rowIndices = prob->hrow_ ; presolvehlink *clink = prob->clink_ ; /* Row bounds and activity, objective. */ double *rlo = prob->rlo_ ; double *rup = prob->rup_ ; double *acts = prob->acts_ ; double *cost = prob->cost_ ; const double tol = prob->feasibilityTolerance_ ; action *actions = new action [ncols] ; # ifdef ZEROFAULT CoinZeroN(reinterpret_cast<char *>(actions),ncols*sizeof(action)) ; # endif int nactions = 0 ; /* This array is used to hold the indices of columns involved in substitutions, where we have the potential for cancellation. At the end they'll be checked to eliminate any actual zeros that may result. At the end of processing of each target row, the column indices of the target row are copied into zerocols. NOTE that usefulColumnInt_ is already in use for parameters implied_free and whichFree when this routine is called from implied_free. */ int *zerocols = new int[ncols] ; int nzerocols = 0 ; int *x_to_y = new int[ncols] ; int *rowsUsed = &prob->usefulRowInt_[0] ; int nRowsUsed = 0 ; /* Open a loop to process the (equality r, implied free variable t) pairs in whichFree and implied_free. It can happen that removal of (row, natural singleton) pairs back in implied_free will reduce the length of column t. It can also happen that previous processing here has resulted in fillin or cancellation. So check again for column length and exclude natural singletons and overly dense columns. */ for (int iLook = 0 ; iLook < numberFree ; iLook++) { const int tgtcol = whichFree[iLook] ; const int tgtcol_len = colLengths[tgtcol] ; const int tgtrow = implied_free[iLook] ; const int tgtrow_len = rowLengths[tgtrow] ; assert(fabs(rlo[tgtrow]-rup[tgtrow]) < tol) ; if (colLengths[tgtcol] < 2 || colLengths[tgtcol] > maxLook) { # if PRESOLVE_DEBUG > 3 std::cout << " skipping eqn " << tgtrow << " x(" << tgtcol << "); length now " << colLengths[tgtcol] << "." << std::endl ; # endif continue ; } CoinBigIndex tgtcs = colStarts[tgtcol] ; CoinBigIndex tgtce = tgtcs+colLengths[tgtcol] ; /* A few checks to make sure that the candidate pair is still suitable. Processing candidates earlier in the list can eliminate coefficients. * Don't use this pair if any involved row i has become a row singleton or empty. * Don't use this pair if any involved row has been modified as part of the processing for a previous candidate pair on this call. * Don't use this pair if a(i,tgtcol) has become zero. The checks on a(i,tgtcol) seem superfluous but it's possible that implied_free identified two candidate pairs to eliminate the same column. If we've already processed one of them, we could be in trouble. */ double tgtcoeff = 0.0 ; bool dealBreaker = false ; for (CoinBigIndex kcol = tgtcs ; kcol < tgtce ; ++kcol) { const int i = rowIndices[kcol] ; if (rowLengths[i] < 2 || prob->rowUsed(i)) { dealBreaker = true ; break ; } const double aij = colCoeffs[kcol] ; if (fabs(aij) <= ZTOLDP2) { dealBreaker = true ; break ; } if (i == tgtrow) tgtcoeff = aij ; } if (dealBreaker == true) { # if PRESOLVE_DEBUG > 3 std::cout << " skipping eqn " << tgtrow << " x(" << tgtcol << "); deal breaker (1)." << std::endl ; # endif continue ; } /* Check for numerical stability.A large coeff_factor will inflate the coefficients in the substitution formula. */ dealBreaker = false ; for (CoinBigIndex kcol = tgtcs ; kcol < tgtce ; ++kcol) { const double coeff_factor = fabs(colCoeffs[kcol]/tgtcoeff) ; if (coeff_factor > 10.0) dealBreaker = true ; } /* Given enough target rows with sufficient overlap, there's an outside chance we could overflow zerocols. Unlikely to ever happen. */ if (!dealBreaker && nzerocols+rowLengths[tgtrow] >= ncols) dealBreaker = true ; if (dealBreaker == true) { # if PRESOLVE_DEBUG > 3 std::cout << " skipping eqn " << tgtrow << " x(" << tgtcol << "); deal breaker (2)." << std::endl ; # endif continue ; } /* If c(t) != 0, we will need to modify the objective coefficients and remember the original objective. */ const bool nonzero_cost = (fabs(cost[tgtcol]) > tol) ; double *costsx = (nonzero_cost?new double[rowLengths[tgtrow]]:0) ; # if PRESOLVE_DEBUG > 1 std::cout << " Eliminating row " << tgtrow << ", col " << tgtcol ; if (nonzero_cost) std::cout << ", cost " << cost[tgtcol] ; std::cout << "." << std::endl ; # endif /* Count up the total number of coefficients in entangled rows and mark them as contaminated. */ int ntotels = 0 ; for (CoinBigIndex kcol = tgtcs ; kcol < tgtce ; ++kcol) { const int i = rowIndices[kcol] ; ntotels += rowLengths[i] ; PRESOLVEASSERT(!prob->rowUsed(i)) ; prob->setRowUsed(i) ; rowsUsed[nRowsUsed++] = i ; } /* Create the postsolve object. Copy in all the affected rows. Take the opportunity to mark the entangled rows as changed and put them on the list of rows to process in the next round. coeffxs in particular holds the coefficients of the target column. */ action *ap = &actions[nactions++] ; ap->col = tgtcol ; ap->rowy = tgtrow ; PRESOLVE_DETAIL_PRINT(printf("pre_subst %dC %dR E\n",tgtcol,tgtrow)) ; ap->nincol = tgtcol_len ; ap->rows = new int[tgtcol_len] ; ap->rlos = new double[tgtcol_len] ; ap->rups = new double[tgtcol_len] ; ap->costsx = costsx ; ap->coeffxs = new double[tgtcol_len] ; ap->ninrowxs = new int[tgtcol_len] ; ap->rowcolsxs = new int[ntotels] ; ap->rowelsxs = new double[ntotels] ; ntotels = 0 ; for (CoinBigIndex kcol = tgtcs ; kcol < tgtce ; ++kcol) { const int ndx = kcol-tgtcs ; const int i = rowIndices[kcol] ; const CoinBigIndex krs = rowStarts[i] ; prob->addRow(i) ; ap->rows[ndx] = i ; ap->ninrowxs[ndx] = rowLengths[i] ; ap->rlos[ndx] = rlo[i] ; ap->rups[ndx] = rup[i] ; ap->coeffxs[ndx] = colCoeffs[kcol] ; CoinMemcpyN(&colIndices[krs],rowLengths[i],&ap->rowcolsxs[ntotels]) ; CoinMemcpyN(&rowCoeffs[krs],rowLengths[i],&ap->rowelsxs[ntotels]) ; ntotels += rowLengths[i] ; } CoinBigIndex tgtrs = rowStarts[tgtrow] ; CoinBigIndex tgtre = tgtrs+rowLengths[tgtrow] ; /* Adjust the objective coefficients based on the substitution formula c'(j) = c(j) - a(rj)c(t)/a(rt) */ if (nonzero_cost) { const double tgtcost = cost[tgtcol] ; for (CoinBigIndex krow = tgtrs ; krow < tgtre ; krow ++) { const int j = colIndices[krow] ; prob->addCol(j) ; costsx[krow-tgtrs] = cost[j] ; double coeff = rowCoeffs[krow] ; cost[j] -= (tgtcost*coeff)/tgtcoeff ; } prob->change_bias(tgtcost*rlo[tgtrow]/tgtcoeff) ; cost[tgtcol] = 0.0 ; } # if PRESOLVE_DEBUG > 1 std::cout << " tgt (" << tgtrow << ") (" << tgtrow_len << "): " ; for (CoinBigIndex krow = tgtrs ; krow < tgtre ; ++krow) { const int j = colIndices[krow] ; const double arj = rowCoeffs[krow] ; std::cout << "x(" << j << ") = " << arj << " (" << colLengths[j] << ") " ; } std::cout << std::endl ; # endif // kill small if wanted int relax= (prob->presolveOptions()&0x60000)>>17; double tolerance = 1.0e-12; for (int i=0;i<relax;i++) tolerance *= 10.0; /* Sort the target row for efficiency when doing elimination. */ CoinSort_2(colIndices+tgtrs,colIndices+tgtre,rowCoeffs+tgtrs) ; /* Get down to the business of substituting for tgtcol in the entangled rows. Open a loop to walk the target column. We walk the saved column because the bulk store can change as we work. We don't want to repeat or miss a row. */ for (int colndx = 0 ; colndx < tgtcol_len ; ++colndx) { int i = ap->rows[colndx] ; if (i == tgtrow) continue ; double ait = ap->coeffxs[colndx] ; double coeff_factor = -ait/tgtcoeff ; CoinBigIndex krs = rowStarts[i] ; CoinBigIndex kre = krs+rowLengths[i] ; # if PRESOLVE_DEBUG > 1 std::cout << " subst pre (" << i << ") (" << rowLengths[i] << "): " ; for (CoinBigIndex krow = krs ; krow < kre ; ++krow) { const int j = colIndices[krow] ; const double aij = rowCoeffs[krow] ; std::cout << "x(" << j << ") = " << aij << " (" << colLengths[j] << ") " ; } std::cout << std::endl ; # endif /* Sort the row for efficiency and call add_row to do the actual business of changing coefficients due to substitution. This has the potential to trigger compaction of the row-major bulk store, so update bulk store indices. */ CoinSort_2(colIndices+krs,colIndices+kre,rowCoeffs+krs) ; bool outOfSpace = add_row(rowStarts,rlo,acts,rup,rowCoeffs,colIndices, rowLengths,rlink,nrows,coeff_factor,tolerance,i,tgtrow, x_to_y) ; if (outOfSpace) throwCoinError("out of memory","CoinImpliedFree::presolve") ; krs = rowStarts[i] ; kre = krs+rowLengths[i] ; tgtrs = rowStarts[tgtrow] ; tgtre = tgtrs+rowLengths[tgtrow] ; # if PRESOLVE_DEBUG > 1 std::cout << " subst aft (" << i << ") (" << rowLengths[i] << "): " ; for (CoinBigIndex krow = krs ; krow < kre ; ++krow) { const int j = colIndices[krow] ; const double aij = rowCoeffs[krow] ; std::cout << "x(" << j << ") = " << aij << " (" << colLengths[j] << ") " ; } std::cout << std::endl ; # endif /* Now update the column-major representation from the row-major representation. This is easy if the coefficient already exists, but painful if there's fillin. presolve_find_row1 will return the index of the row in the column vector, or one past the end if it's missing. If the coefficient is fill, presolve_expand_col will make sure that there's room in the column for one more coefficient. This may require that the column be moved in the bulk store, so we need to update kcs and kce. Once we're done, a(it) = 0 (i.e., we've eliminated x(t) from row i). Physically remove the explicit zero from the row-major representation with presolve_delete_from_row. */ for (CoinBigIndex rowndx = 0 ; rowndx < tgtrow_len ; ++rowndx) { const CoinBigIndex ktgt = tgtrs+rowndx ; const int j = colIndices[ktgt] ; CoinBigIndex kcs = colStarts[j] ; CoinBigIndex kce = kcs+colLengths[j] ; assert(colIndices[krs+x_to_y[rowndx]] == j) ; const double coeff = rowCoeffs[krs+x_to_y[rowndx]] ; CoinBigIndex kcol = presolve_find_row1(i,kcs,kce,rowIndices) ; if (kcol < kce) { colCoeffs[kcol] = coeff ; } else { outOfSpace = presolve_expand_col(colStarts,colCoeffs,rowIndices, colLengths,clink,ncols,j) ; if (outOfSpace) throwCoinError("out of memory","CoinImpliedFree::presolve") ; kcs = colStarts[j] ; kce = kcs+colLengths[j] ; rowIndices[kce] = i ; colCoeffs[kce] = coeff ; colLengths[j]++ ; } } presolve_delete_from_row(i,tgtcol, rowStarts,rowLengths,colIndices,rowCoeffs) ; # if PRESOLVE_DEBUG > 1 kre-- ; std::cout << " subst fin (" << i << ") (" << rowLengths[i] << "): " ; for (CoinBigIndex krow = krs ; krow < kre ; ++krow) { const int j = colIndices[krow] ; const double aij = rowCoeffs[krow] ; std::cout << "x(" << j << ") = " << aij << " (" << colLengths[j] << ") " ; } std::cout << std::endl ; # endif } /* End of the substitution loop. Record the column indices of the target row so we can groom these columns later to remove possible explicit zeros. */ CoinMemcpyN(&colIndices[rowStarts[tgtrow]],rowLengths[tgtrow], &zerocols[nzerocols]) ; nzerocols += rowLengths[tgtrow] ; /* Remove the target equality from the column- and row-major representations Somewhat painful in the colum-major representation. We have to walk the target row in the row-major representation and look up each coefficient in the column-major representation. */ for (CoinBigIndex krow = tgtrs ; krow < tgtre ; ++krow) { const int j = colIndices[krow] ; # if PRESOLVE_DEBUG > 1 std::cout << " removing row " << tgtrow << " from col " << j << std::endl ; # endif presolve_delete_from_col(tgtrow,j, colStarts,colLengths,rowIndices,colCoeffs) ; if (colLengths[j] == 0) { PRESOLVE_REMOVE_LINK(clink,j) ; } } /* Finally, physically remove the column from the column-major representation and the row from the row-major representation. */ PRESOLVE_REMOVE_LINK(clink, tgtcol) ; colLengths[tgtcol] = 0 ; PRESOLVE_REMOVE_LINK(rlink, tgtrow) ; rowLengths[tgtrow] = 0 ; rlo[tgtrow] = 0.0 ; rup[tgtrow] = 0.0 ; # if PRESOLVE_CONSISTENCY > 0 presolve_links_ok(prob) ; presolve_consistent(prob) ; # endif } /* That's it, we've processed all the candidate pairs. Clear the row used flags. */ for (int i = 0 ; i < nRowsUsed ; i++) prob->unsetRowUsed(rowsUsed[i]) ; /* Trim the array of substitution transforms and queue up objects for postsolve. Also groom the problem representation to remove explicit zeros. */ if (nactions) { # if PRESOLVE_SUMMARY > 0 std::cout << "NSUBSTS: " << nactions << std::endl ; # endif next = new subst_constraint_action(nactions, CoinCopyOfArray(actions,nactions),next) ; next = drop_zero_coefficients_action::presolve(prob,zerocols, nzerocols, next) ; # if PRESOLVE_CONSISTENCY > 0 presolve_links_ok(prob) ; presolve_consistent(prob) ; # endif } deleteAction(actions,action*) ; delete [] x_to_y ; delete [] zerocols ; # if COIN_PRESOLVE_TUNING > 0 if (prob->tuning_) double thisTime = CoinCpuTime() ; # endif # if PRESOLVE_CONSISTENCY > 0 || PRESOLVE_DEBUG > 0 presolve_check_sol(prob) ; # endif # if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING > 0 int droppedRows = prob->countEmptyRows()-startEmptyRows ; int droppedColumns = prob->countEmptyCols()-startEmptyColumns ; std::cout << "Leaving subst_constraint_action::presolve, " << droppedRows << " rows, " << droppedColumns << " columns dropped" ; # if COIN_PRESOLVE_TUNING > 0 std::cout << " in " << thisTime-startTime << "s" ; # endif std::cout << "." << std::endl ; # endif return (next) ; }
int main (int argc, const char *argv[]) { OsiClpSolverInterface solver1; /* We are going to treat x1 and x2 as integer and x3 and x4 as a set. We define two new variables y1 == x1*x4 and y2 == x2*x3. We define a variable z == x1*x4/x2*x3 so y2*z == y1 (we will treat y2 as a set) Then we have objective - minimize w1 + w2 where w1 - w2 = 1.0/6.931 - z The model would be a lot smaller if we had column generation. */ // Create model CoinModel build; // Keep values of all variables for reporting purposes even if not necessary /* z is first, then x then y1,y2 then w1,w2 then y1 stuff, y2 stuff and finally y2 -> z stuff. For rows same but 2 per y then rest of z stuff */ int loInt=12; int hiInt=60; int ybaseA=5, ybaseB=9, ylen=hiInt-loInt+1; int base = ybaseB+2*2*ylen; int yylen = hiInt*hiInt-loInt*loInt+1; int zbase = 10; int i; // Do single variables double value[] ={1.0,1.0}; int row[2]; /* z - obviously we can't choose bounds too tight but we need bounds so choose 20% off as obviously feasible. fastest way to solve would be too run for a few seconds to get tighter bounds then re-formulate and solve. */ double loose=0.2; double loZ = (1-loose)*(1.0/6.931), hiZ = (1+loose)*(1.0/6.931); row[0]=0; // for reporting row[1]=zbase+1; // for real use build.addColumn(2,row,value,loZ, hiZ, 0.0); // x for (i=0;i<4;i++) { row[0]=i+1; build.addColumn(1,row,value,loInt, hiInt,0.0); // we don't need to say x2, x3 integer but won't hurt build.setInteger(i+1); } // y for (i=0;i<2;i++) { // y from x*x, and convexity row[0]=ybaseA+2*i; if (i==0) row[1]=zbase+2; // yb*z == ya else row[1]=zbase-1; // to feed into z build.addColumn(2,row,value,loInt*loInt, hiInt*hiInt,0.0); // we don't need to say integer but won't hurt build.setInteger(ybaseA+i); } // skip z convexity put w in final equation row[0]=zbase+1; build.addColumn(1,row,value,0.0,1.0,1.0); value[0]=-1.0; build.addColumn(1,row,value,0.0,1.0,1.0); // Do columns so we know where each is for (i=ybaseB;i<base+(2*yylen);i++) build.setColumnBounds(i,0.0,1.0); // Now do rows // z definition build.setRowBounds(0,0.0,0.0); for (i=0;i<yylen;i++) { // l build.setElement(0,base+2*i,-loZ); // u build.setElement(0,base+2*i+1,-hiZ); } // x for (i=0;i<2;i++) { int iVarRow = 1+i; int iSetRow = 4-i; // as it is x1*x4 and x2*x3 build.setRowBounds(iVarRow,0.0,0.0); build.setRowBounds(iSetRow,0.0,0.0); int j; int base2 = ybaseB + 2*ylen*i; for (j=0;j<ylen;j++) { // l build.setElement(iVarRow,base2+2*j,-loInt); build.setElement(iSetRow,base2+2*j,-loInt-j); // u build.setElement(iVarRow,base2+2*j+1,-hiInt); build.setElement(iSetRow,base2+2*j+1,-loInt-j); } } // y for (i=0;i<2;i++) { int iRow = 5+2*i; int iConvex = iRow+1; build.setRowBounds(iRow,0.0,0.0); build.setRowBounds(iConvex,1.0,1.0); int j; int base2 = ybaseB + 2*ylen*i; for (j=0;j<ylen;j++) { // l build.setElement(iRow,base2+2*j,-loInt*(j+loInt)); build.setElement(iConvex,base2+2*j,1.0); // u build.setElement(iRow,base2+2*j+1,-hiInt*(j+loInt)); build.setElement(iConvex,base2+2*j+1,1.0); } } // row that feeds into z and convexity build.setRowBounds(zbase-1,0.0,0.0); build.setRowBounds(zbase,1.0,1.0); for (i=0;i<yylen;i++) { // l build.setElement(zbase-1,base+2*i,-(i+loInt*loInt)); build.setElement(zbase,base+2*i,1.0); // u build.setElement(zbase-1,base+2*i+1,-(i+loInt*loInt)); build.setElement(zbase,base+2*i+1,1.0); } // and real equation rhs build.setRowBounds(zbase+1,1.0/6.931,1.0/6.931); // z*y build.setRowBounds(zbase+2,0.0,0.0); for (i=0;i<yylen;i++) { // l build.setElement(zbase+2,base+2*i,-(i+loInt*loInt)*loZ); // u build.setElement(zbase+2,base+2*i+1,-(i+loInt*loInt)*hiZ); } // And finally two more rows to break symmetry build.setRowBounds(zbase+3,-COIN_DBL_MAX,0.0); build.setElement(zbase+3,1,1.0); build.setElement(zbase+3,4,-1.0); build.setRowBounds(zbase+4,-COIN_DBL_MAX,0.0); build.setElement(zbase+4,2,1.0); build.setElement(zbase+4,3,-1.0); solver1.loadFromCoinModel(build); // To make CbcBranchLink simpler assume that all variables with same i are consecutive double time1 = CoinCpuTime(); solver1.initialSolve(); solver1.writeMps("bad"); CbcModel model(solver1); model.solver()->setHintParam(OsiDoReducePrint,true,OsiHintTry); model.solver()->setHintParam(OsiDoScale,false,OsiHintTry); CbcObject ** objects = new CbcObject * [3]; /* Format is number in sets, number in each link, first variable in matrix) and then a weight for each in set to say where to branch. In this case use NULL to say 0,1,2 ... Finally a set number as ID. */ objects[0]=new CbcLink(&model,ylen,2,ybaseB,NULL,0); objects[0]->setPriority(10); objects[1]=new CbcLink(&model,ylen,2,ybaseB+2*ylen,NULL,0); objects[1]->setPriority(20); objects[2]=new CbcLink(&model,yylen,2,base,NULL,0); objects[2]->setPriority(1); model.addObjects(3,objects); for (i=0;i<3;i++) delete objects[i]; delete [] objects; model.messageHandler()->setLogLevel(1); // Do complete search model.setDblParam(CbcModel::CbcMaximumSeconds,1200.0); model.setDblParam(CbcModel::CbcCutoffIncrement,1.0e-8); model.branchAndBound(); std::cout<<"took "<<CoinCpuTime()-time1<<" seconds, " <<model.getNodeCount()<<" nodes with objective " <<model.getObjValue() <<(!model.status() ? " Finished" : " Not finished") <<std::endl; if (model.getMinimizationObjValue()<1.0e50) { const double * solution = model.bestSolution(); int numberColumns = model.solver()->getNumCols(); double x1=solution[1]; double x2=solution[2]; double x3=solution[3]; double x4=solution[4]; printf("Optimal solution %g %g %g %g\n",x1,x2,x3,x4); for (int iColumn=0;iColumn<numberColumns;iColumn++) { double value=solution[iColumn]; if (fabs(value)>1.0e-7) std::cout<<iColumn<<" "<<value<<std::endl; } } return 0; }
bool BlisHeurRound::searchSolution(double & solutionValue, double * betterSolution) { bool foundBetter = false; if (strategy_ == -2) { // This heuristic has been disabled. return foundBetter; } //------------------------------------------------------ // Start to search solution ... //------------------------------------------------------ double start = CoinCpuTime(); // Get a copy of original matrix (and by row for rounding); matrix_ = *(model_->solver()->getMatrixByCol()); matrixByRow_ = *(model_->solver()->getMatrixByRow()); seed_ = 1; OsiSolverInterface * solver = model_->solver(); 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 = 1.0e-5; //model_->getDblParam(BlisModel::BlisIntegerTolerance); double primalTolerance; solver->getDblParam(OsiPrimalTolerance, primalTolerance); int numberRows = matrix_.getNumRows(); int numberIntegers = model_->getNumIntVars(); const int * integerVariable = model_->getIntVars(); int i; double direction = solver->getObjSense(); double newSolutionValue = direction * solver->getObjValue(); // Column copy const double * element = matrix_.getElements(); const int * row = matrix_.getIndices(); const int * columnStart = matrix_.getVectorStarts(); const int * columnLength = matrix_.getVectorLengths(); // Row copy const double * elementByRow = matrixByRow_.getElements(); const int * column = matrixByRow_.getIndices(); const int * rowStart = matrixByRow_.getVectorStarts(); const int * rowLength = matrixByRow_.getVectorLengths(); // Get solution array for heuristic solution int numberColumns = solver->getNumCols(); double * newSolution = new double [numberColumns]; memcpy(newSolution, solution, numberColumns * sizeof(double)); double * rowActivity = new double[numberRows]; memset(rowActivity, 0, numberRows*sizeof(double)); for (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 feasible - if not adjust (cleaning may move) for (i = 0; i < numberRows; i++) { if(rowActivity[i] < rowLower[i]) { //assert (rowActivity[i]>rowLower[i]-1000.0*primalTolerance); rowActivity[i] = rowLower[i]; } else if(rowActivity[i] > rowUpper[i]) { //assert (rowActivity[i]<rowUpper[i]+1000.0*primalTolerance); rowActivity[i] = rowUpper[i]; } } for (i = 0; i < numberIntegers; i++) { int iColumn = integerVariable[i]; double value = newSolution[iColumn]; if (fabs(floor(value + 0.5) - value) > integerTolerance) { double below = floor(value); double newValue = newSolution[iColumn]; double cost = direction * objective[iColumn]; double move; if (cost > 0.0) { // try up move = 1.0 - (value - below); } else if (cost < 0.0) { // try down move = below - value; } else { // won't be able to move unless we can grab another variable // just for now go down move = below-value; } newValue += move; newSolution[iColumn] = newValue; newSolutionValue += move * cost; int j; for (j = columnStart[iColumn]; j < columnStart[iColumn] + columnLength[iColumn]; j++) { int iRow = row[j]; rowActivity[iRow] += move * element[j]; } } } double penalty = 0.0; // see if feasible for (i = 0; i < numberRows; i++) { double value = rowActivity[i]; double thisInfeasibility = 0.0; if (value < rowLower[i] - primalTolerance) thisInfeasibility = value - rowLower[i]; else if (value > rowUpper[i] + primalTolerance) thisInfeasibility = value - rowUpper[i]; if (thisInfeasibility) { // See if there are any slacks I can use to fix up // maybe put in coding for multiple slacks? double bestCost = 1.0e50; int k; int iBest = -1; double addCost = 0.0; double newValue = 0.0; double changeRowActivity = 0.0; double absInfeasibility = fabs(thisInfeasibility); for (k = rowStart[i]; k < rowStart[i] + rowLength[i]; k++) { int iColumn = column[k]; if (columnLength[iColumn] == 1) { double currentValue = newSolution[iColumn]; double elementValue = elementByRow[k]; double lowerValue = lower[iColumn]; double upperValue = upper[iColumn]; double gap = rowUpper[i] - rowLower[i]; double absElement = fabs(elementValue); if (thisInfeasibility * elementValue > 0.0) { // we want to reduce if ((currentValue - lowerValue) * absElement >= absInfeasibility) { // possible - check if integer double distance = absInfeasibility / absElement; double thisCost = -direction * objective[iColumn] * distance; if (solver->isInteger(iColumn)) { distance = ceil(distance - primalTolerance); assert (currentValue - distance >= lowerValue - primalTolerance); if (absInfeasibility - distance * absElement < -gap - primalTolerance) thisCost = 1.0e100; // no good else thisCost = -direction*objective[iColumn]*distance; } if (thisCost < bestCost) { bestCost = thisCost; iBest = iColumn; addCost = thisCost; newValue = currentValue - distance; changeRowActivity = -distance * elementValue; } } } else { // we want to increase if ((upperValue - currentValue) * absElement >= absInfeasibility) { // possible - check if integer double distance = absInfeasibility / absElement; double thisCost = direction * objective[iColumn] * distance; if (solver->isInteger(iColumn)) { distance = ceil(distance - 1.0e-7); assert (currentValue - distance <= upperValue + primalTolerance); if (absInfeasibility - distance * absElement < -gap - primalTolerance) thisCost = 1.0e100; // no good else thisCost = direction*objective[iColumn]*distance; } if (thisCost < bestCost) { bestCost = thisCost; iBest = iColumn; addCost = thisCost; newValue = currentValue + distance; changeRowActivity = distance * elementValue; } } } } } if (iBest >= 0) { /*printf("Infeasibility of %g on row %d cost %g\n", thisInfeasibility,i,addCost);*/ newSolution[iBest] = newValue; thisInfeasibility = 0.0; newSolutionValue += addCost; rowActivity[i] += changeRowActivity; } penalty += fabs(thisInfeasibility); } } // Could also set SOS (using random) and repeat if (!penalty) { // Got a feasible solution. Try to improve. //seed_++; //CoinSeedRandom(seed_); // Random number between 0 and 1. double randomNumber = CoinDrand48(); int iPass; int start[2]; int end[2]; int iRandom = (int) (randomNumber * ((double) numberIntegers)); start[0] = iRandom; end[0] = numberIntegers; start[1] = 0; end[1] = iRandom; for (iPass = 0; iPass < 2; iPass++) { int i; for (i = start[iPass]; i < end[iPass]; i++) { int iColumn = integerVariable[i]; #ifdef BLIS_DEBUG double value = newSolution[iColumn]; assert(fabs(floor(value + 0.5) - value) < integerTolerance); #endif double cost = direction * objective[iColumn]; double move = 0.0; if (cost > 0.0) move = -1.0; else if (cost < 0.0) move = 1.0; while (move) { bool good = true; double newValue = newSolution[iColumn] + move; if (newValue < lower[iColumn] - primalTolerance|| newValue > upper[iColumn] + primalTolerance) { move = 0.0; } else { // see if we can move int j; for (j = columnStart[iColumn]; j < columnStart[iColumn] + columnLength[iColumn]; j++) { int iRow = row[j]; double newActivity = rowActivity[iRow] + move*element[j]; if (newActivity < rowLower[iRow] - primalTolerance || newActivity > rowUpper[iRow]+primalTolerance) { good = false; break; } } if (good) { newSolution[iColumn] = newValue; newSolutionValue += move * cost; int j; for (j = columnStart[iColumn]; j < columnStart[iColumn] + columnLength[iColumn]; j++) { int iRow = row[j]; rowActivity[iRow] += move*element[j]; } } else { move=0.0; } } } } } if (newSolutionValue < solutionValue) { // paranoid check memset(rowActivity, 0, numberRows * sizeof(double)); for (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 (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; } } if (feasible) { // new solution memcpy(betterSolution, newSolution, numberColumns * sizeof(double)); solutionValue = newSolutionValue; //printf("** Solution of %g found by rounding\n",newSolutionValue); foundBetter = true; } else { // Can easily happen //printf("Debug BlisHeurRound giving bad solution\n"); } } } delete [] newSolution; delete [] rowActivity; //------------------------------------------------------ // Update statistics. //------------------------------------------------------ ++calls_; if (foundBetter) ++numSolutions_; time_ += (CoinCpuTime() - start); return foundBetter; }
/* This is a utility function which does strong branching on one nway object and stores the results in appropriate arrays of the class and maybe more. It returns - -1 - branch was infeasible both ways 0 - nothing can be fixed 1 - object can be fixed (returnCriterion==0) 3 - time limit */ int BonNWayChoose::doStrongBranching( OsiSolverInterface * solver, OsiBranchingInformation *info, int objectIndex, double * saveLower, double * saveUpper, double & score) { int nwayIndex = objectIndex - start_nway_; const double * lower = info->lower_; const double * upper = info->upper_; int numberColumns = solver->getNumCols(); double timeStart = CoinCpuTime(); int numberObjects = info->solver_->numberObjects(); const BonNWayObject * nway = ASSERTED_CAST<const BonNWayObject *>(solver->object(objectIndex)); assert(nway); BonNWayBranchingObject * branch = ASSERTED_CAST<BonNWayBranchingObject *>(nway->createBranch(solver, info, 1)); int branches_left = branch->numberBranchesLeft(); int number_branches = branch->numberBranchesLeft(); int n_can_be_fixed = 0; double big_val = cutoff_multiplier_*info->cutoff_;// For infeasibles if(big_val > 1e10){ big_val = 10*info->objectiveValue_;} big_val += fabs(big_val)*1e-5; std::vector<double> unit_changes(numberObjects - start_nway_, -DBL_MAX); //std::vector<double> unit_changes(numberObjects - start_nway_, 0); while(branches_left){ branch->branch(solver); int v_br = branch->var_branched_on(); int s_br = branch->seq_branched_on(); double residual = upper[v_br] - info->solution_[v_br]; solver->solveFromHotStart() ; numberStrongIterations_ += solver->getIterationCount(); numberStrongDone_++; double obj_val = solver->getObjValue(); if(solver->isProvenPrimalInfeasible() || (solver->isProvenOptimal() && obj_val > info->cutoff_)){//infeasible if(info->depth_ == 0){ bounds_[nwayIndex][s_br] = big_val; } unit_changes[s_br] = (big_val - info->objectiveValue_)/residual; if(do_fixings_ > 1){ n_can_be_fixed++; if(log_ > 0) printf("Fixing variable %i to 0 the cutoff is %g\n", v_br, big_val); saveUpper[v_br] = saveLower[v_br]; } } else{ if(info->depth_ == 0){ bounds_[nwayIndex][s_br] = obj_val; } unit_changes[s_br] = (obj_val - info->objectiveValue_)/residual; } // Restore bounds for (int j=0;j<numberColumns;j++) { if (saveLower[j] != lower[j]) solver->setColLower(j,saveLower[j]); if (saveUpper[j] != upper[j]) solver->setColUpper(j,saveUpper[j]); } branches_left = branch->numberBranchesLeft(); } score = compute_usefulness(info, nway->numberMembers(), nway->members(), bounds_[nwayIndex], unit_changes); if(info->depth_ == 0){//At root bounds contains valid bound on obj after branching, remember if(do_fixings_ == 1 || do_fixings_ == 3) nway->set_bounds(bounds_[nwayIndex]); for(size_t k = 0 ; k < unit_changes.size() ; k++){ num_ps_costs_[nwayIndex][k]=1; } unit_changes_[nwayIndex] = unit_changes; num_eval_[nwayIndex] = 1; } else if (n_can_be_fixed < number_branches -1){ num_eval_[nwayIndex]++; for(size_t k = 0 ; k < unit_changes.size() ; k++){ if(unit_changes[k] > 0.){ if(geo_means_) unit_changes_[nwayIndex][k] *= unit_changes[k]; else unit_changes_[nwayIndex][k] += unit_changes[k]; num_ps_costs_[nwayIndex][k]++; } } } if(n_can_be_fixed == number_branches){ return -1; } if(n_can_be_fixed){ return 1; } bool hitMaxTime = ( CoinCpuTime()-timeStart > info->timeRemaining_) || ( CoinCpuTime() - start_time_ > time_limit_); if (hitMaxTime) { return 3; } return 0; }
int main (int argc, const char *argv[]) { // Define your favorite OsiSolver OsiClpSolverInterface solver1; //solver1.messageHandler()->setLogLevel(0); CbcModel model(solver1); model.solver()->setHintParam(OsiDoReducePrint,true,OsiHintTry); // Read in rgn.mps std::string mpsFileName; #if defined(MIPLIB3DIR) mpsFileName = MIPLIB3DIR "/rgn"; #else if (argc < 2) { fprintf(stderr, "Do not know where to find miplib3 MPS files.\n"); exit(1); } #endif if (argc>=2) mpsFileName = argv[1]; int numMpsReadErrors = model.solver()->readMps(mpsFileName.c_str(),""); if( numMpsReadErrors != 0 ) { printf("%d errors reading MPS file\n", numMpsReadErrors); return numMpsReadErrors; } // Definition of node choice CbcCompareUser compare; compare.setWeight(0.0); model.setNodeComparison(compare); // Reduce output model.messageHandler()->setLogLevel(1); // Get branching messages model.messageHandler()->setLogLevel(3); // Do initial solve to continuous model.initialSolve(); // Save model CbcModel model2 = model; int numberColumns=model.getNumCols(); int numberIntegers = 0; int * integerVariable = new int[numberColumns]; int i; for ( i=0;i<numberColumns;i++) { if (model.isInteger(i)) { integerVariable[numberIntegers++]=i; } } if (numberColumns!=180 || numberIntegers!=100) { printf("Incorrect model for example\n"); exit(1); } double time1 = CoinCpuTime() ; model.branchAndBound(); std::cout<<"rgn.mps"<<" took "<<CoinCpuTime()-time1<<" seconds, " <<model.getNodeCount()<<" nodes with objective " <<model.getObjValue() <<(!model.status() ? " Finished" : " Not finished") <<std::endl; const double * solution = model.solver()->getColSolution(); std::cout<<std::setiosflags(std::ios::fixed|std::ios::showpoint)<<std::setw(14); std::cout<<"--------------------------------------"<<std::endl; for (i=0;i<numberIntegers;i++) { int iColumn = integerVariable[i]; double value=solution[iColumn]; if (fabs(value)>1.0e-7) 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); // Restore model model = model2; // Convert slacks to variables CoinBigIndex start[5]={0,1,2,3,4}; int row[4]={0,1,2,3}; double element[4]={1.0,1.0,1.0,1.0}; double up[4]={1.0,1.0,1.0,1.0}; model.solver()->addCols(4,start,row,element,NULL,up,NULL); // Now use SOS1 int numberSets=4; int which[104]; double weights[104]; int starts[5]; // load int n=0; starts[0]=0; for (int iSet=0;iSet<4;iSet++) { for (int i=0;i<25;i++) { weights[n]=i+1.0; which[n]=iSet*25+i; n++; } // slack - make sure first branch is on slack weights[n]=1000.0; which[n]=180+iSet; n++; starts[iSet+1]=n; } for (i=0;i<numberIntegers;i++) { int iColumn = integerVariable[i]; // Stop being integer model.solver()->setContinuous(iColumn); } // save model in this state CbcModel modelSOS = model; CbcObject ** objects = new CbcObject * [numberSets]; for (i=0;i<numberSets;i++) { objects[i]= new CbcSOS(&model,starts[i+1]-starts[i],which+starts[i], weights,i); } model.addObjects(numberSets,objects); for (i=0;i<numberSets;i++) delete objects[i]; delete [] objects; time1 = CoinCpuTime() ; model.branchAndBound(); std::cout<<"rgn.mps"<<" took "<<CoinCpuTime()-time1<<" seconds, " <<model.getNodeCount()<<" nodes with objective " <<model.getObjValue() <<(!model.status() ? " Finished" : " Not finished") <<std::endl; solution = model.solver()->getColSolution(); std::cout<<std::setiosflags(std::ios::fixed|std::ios::showpoint)<<std::setw(14); std::cout<<"--------------------------------------"<<std::endl; for (i=0;i<numberIntegers;i++) { int iColumn = integerVariable[i]; double value=solution[iColumn]; if (fabs(value)>1.0e-7) 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); // Restore SOS model model = modelSOS; // Now use SOS2 objects = new CbcObject * [numberSets]; for (i=0;i<numberSets;i++) { objects[i]= new CbcSOS(&model,starts[i+1]-starts[i],which+starts[i], weights,i,2); } model.addObjects(numberSets,objects); for (i=0;i<numberSets;i++) delete objects[i]; delete [] objects; time1 = CoinCpuTime() ; model.branchAndBound(); std::cout<<"rgn.mps"<<" took "<<CoinCpuTime()-time1<<" seconds, " <<model.getNodeCount()<<" nodes with objective " <<model.getObjValue() <<(!model.status() ? " Finished" : " Not finished") <<std::endl; solution = model.solver()->getColSolution(); std::cout<<std::setiosflags(std::ios::fixed|std::ios::showpoint)<<std::setw(14); std::cout<<"--------------------------------------"<<std::endl; for (i=0;i<numberIntegers;i++) { int iColumn = integerVariable[i]; double value=solution[iColumn]; if (fabs(value)>1.0e-7) 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); delete [] integerVariable; return 0; }
int main(int argc, const char *argv[]) { { // Empty model ClpSimplex model; // Bounds on rows - as dense vector double lower[] = {2.0, 1.0}; double upper[] = {COIN_DBL_MAX, 1.0}; // Create space for 2 rows model.resize(2, 0); // Fill in int i; // Now row bounds for (i = 0; i < 2; i++) { model.setRowLower(i, lower[i]); model.setRowUpper(i, upper[i]); } // Now add column 1 int column1Index[] = {0, 1}; double column1Value[] = {1.0, 1.0}; model.addColumn(2, column1Index, column1Value, 0.0, 2, 1.0); // Now add column 2 int column2Index[] = {1}; double column2Value[] = { -5.0}; model.addColumn(1, column2Index, column2Value, 0.0, COIN_DBL_MAX, 0.0); // Now add column 3 int column3Index[] = {0, 1}; double column3Value[] = {1.0, 1.0}; model.addColumn(2, column3Index, column3Value, 0.0, 4.0, 4.0); // solve model.dual(); /* Adding one column at a time has a significant overhead so let's try a more complicated but faster way First time adding in 10000 columns one by one */ model.allSlackBasis(); ClpSimplex modelSave = model; double time1 = CoinCpuTime(); int k; for (k = 0; k < 10000; k++) { int column2Index[] = {0, 1}; double column2Value[] = {1.0, -5.0}; model.addColumn(2, column2Index, column2Value, 0.0, 1.0, 10000.0); } printf("Time for 10000 addColumn is %g\n", CoinCpuTime() - time1); model.dual(); model = modelSave; // Now use build CoinBuild buildObject; time1 = CoinCpuTime(); for (k = 0; k < 100000; k++) { int column2Index[] = {0, 1}; double column2Value[] = {1.0, -5.0}; buildObject.addColumn(2, column2Index, column2Value, 0.0, 1.0, 10000.0); } model.addColumns(buildObject); printf("Time for 100000 addColumn using CoinBuild is %g\n", CoinCpuTime() - time1); model.dual(); model = modelSave; // Now use build +-1 int del[] = {0, 1, 2}; model.deleteColumns(3, del); CoinBuild buildObject2; time1 = CoinCpuTime(); for (k = 0; k < 10000; k++) { int column2Index[] = {0, 1}; double column2Value[] = {1.0, 1.0, -1.0}; int bias = k & 1; buildObject2.addColumn(2, column2Index, column2Value + bias, 0.0, 1.0, 10000.0); } model.addColumns(buildObject2, true); printf("Time for 10000 addColumn using CoinBuild+-1 is %g\n", CoinCpuTime() - time1); model.dual(); model = modelSave; // Now use build +-1 model.deleteColumns(3, del); CoinModel modelObject2; time1 = CoinCpuTime(); for (k = 0; k < 10000; k++) { int column2Index[] = {0, 1}; double column2Value[] = {1.0, 1.0, -1.0}; int bias = k & 1; modelObject2.addColumn(2, column2Index, column2Value + bias, 0.0, 1.0, 10000.0); } model.addColumns(modelObject2, true); printf("Time for 10000 addColumn using CoinModel+-1 is %g\n", CoinCpuTime() - time1); //model.writeMps("xx.mps"); model.dual(); model = modelSave; // Now use model CoinModel modelObject; time1 = CoinCpuTime(); for (k = 0; k < 100000; k++) { int column2Index[] = {0, 1}; double column2Value[] = {1.0, -5.0}; modelObject.addColumn(2, column2Index, column2Value, 0.0, 1.0, 10000.0); } model.addColumns(modelObject); printf("Time for 100000 addColumn using CoinModel is %g\n", CoinCpuTime() - time1); model.dual(); // Print column solution Just first 3 columns int numberColumns = model.numberColumns(); numberColumns = CoinMin(3, numberColumns); // Alternatively getColSolution() double * columnPrimal = model.primalColumnSolution(); // Alternatively getReducedCost() double * columnDual = model.dualColumnSolution(); // Alternatively getColLower() double * columnLower = model.columnLower(); // Alternatively getColUpper() double * columnUpper = model.columnUpper(); // Alternatively getObjCoefficients() double * columnObjective = model.objective(); int iColumn; std::cout << " Primal Dual Lower Upper Cost" << std::endl; for (iColumn = 0; iColumn < numberColumns; iColumn++) { double value; std::cout << std::setw(6) << iColumn << " "; value = columnPrimal[iColumn]; if (fabs(value) < 1.0e5) std::cout << std::setiosflags(std::ios::fixed | std::ios::showpoint) << std::setw(14) << value; else std::cout << std::setiosflags(std::ios::scientific) << std::setw(14) << value; value = columnDual[iColumn]; if (fabs(value) < 1.0e5) std::cout << std::setiosflags(std::ios::fixed | std::ios::showpoint) << std::setw(14) << value; else std::cout << std::setiosflags(std::ios::scientific) << std::setw(14) << value; value = columnLower[iColumn]; if (fabs(value) < 1.0e5) std::cout << std::setiosflags(std::ios::fixed | std::ios::showpoint) << std::setw(14) << value; else std::cout << std::setiosflags(std::ios::scientific) << std::setw(14) << value; value = columnUpper[iColumn]; if (fabs(value) < 1.0e5) std::cout << std::setiosflags(std::ios::fixed | std::ios::showpoint) << std::setw(14) << value; else std::cout << std::setiosflags(std::ios::scientific) << std::setw(14) << value; value = columnObjective[iColumn]; if (fabs(value) < 1.0e5) std::cout << std::setiosflags(std::ios::fixed | std::ios::showpoint) << std::setw(14) << value; else std::cout << std::setiosflags(std::ios::scientific) << std::setw(14) << value; std::cout << std::endl; } std::cout << "--------------------------------------" << std::endl; } { // Now copy a model ClpSimplex model; int status; if (argc < 2) { #if defined(SAMPLEDIR) status = model.readMps(SAMPLEDIR "/p0033.mps", true); #else fprintf(stderr, "Do not know where to find sample MPS files.\n"); exit(1); #endif } else status = model.readMps(argv[1]); if (status) { printf("errors on input\n"); exit(77); } model.initialSolve(); int numberRows = model.numberRows(); int numberColumns = model.numberColumns(); const double * rowLower = model.rowLower(); const double * rowUpper = model.rowUpper(); // Start off model2 ClpSimplex model2; model2.addRows(numberRows, rowLower, rowUpper, NULL); // Build object CoinBuild buildObject; // Add columns const double * columnLower = model.columnLower(); const double * columnUpper = model.columnUpper(); const double * objective = model.objective(); CoinPackedMatrix * matrix = model.matrix(); const int * row = matrix->getIndices(); const int * columnLength = matrix->getVectorLengths(); const CoinBigIndex * columnStart = matrix->getVectorStarts(); const double * elementByColumn = matrix->getElements(); for (int iColumn = 0; iColumn < numberColumns; iColumn++) { CoinBigIndex start = columnStart[iColumn]; buildObject.addColumn(columnLength[iColumn], row + start, elementByColumn + start, columnLower[iColumn], columnUpper[iColumn], objective[iColumn]); } // add in model2.addColumns(buildObject); model2.initialSolve(); } { // and again ClpSimplex model; int status; if (argc < 2) { #if defined(SAMPLEDIR) status = model.readMps(SAMPLEDIR "/p0033.mps", true); #else fprintf(stderr, "Do not know where to find sample MPS files.\n"); exit(1); #endif } else status = model.readMps(argv[1]); if (status) { printf("errors on input\n"); exit(77); } model.initialSolve(); int numberRows = model.numberRows(); int numberColumns = model.numberColumns(); const double * rowLower = model.rowLower(); const double * rowUpper = model.rowUpper(); // Build object CoinModel buildObject; for (int iRow = 0; iRow < numberRows; iRow++) buildObject.setRowBounds(iRow, rowLower[iRow], rowUpper[iRow]); // Add columns const double * columnLower = model.columnLower(); const double * columnUpper = model.columnUpper(); const double * objective = model.objective(); CoinPackedMatrix * matrix = model.matrix(); const int * row = matrix->getIndices(); const int * columnLength = matrix->getVectorLengths(); const CoinBigIndex * columnStart = matrix->getVectorStarts(); const double * elementByColumn = matrix->getElements(); for (int iColumn = 0; iColumn < numberColumns; iColumn++) { CoinBigIndex start = columnStart[iColumn]; buildObject.addColumn(columnLength[iColumn], row + start, elementByColumn + start, columnLower[iColumn], columnUpper[iColumn], objective[iColumn]); } // add in ClpSimplex model2; model2.loadProblem(buildObject); model2.initialSolve(); } return 0; }
const CoinPresolveAction *do_tighten_action::presolve(CoinPresolveMatrix *prob, const CoinPresolveAction *next) { double *colels = prob->colels_; int *hrow = prob->hrow_; CoinBigIndex *mcstrt = prob->mcstrt_; int *hincol = prob->hincol_; int ncols = prob->ncols_; double *clo = prob->clo_; double *cup = prob->cup_; double *rlo = prob->rlo_; double *rup = prob->rup_; double *dcost = prob->cost_; const unsigned char *integerType = prob->integerType_; int *fix_cols = prob->usefulColumnInt_; int nfixup_cols = 0; int nfixdown_cols = ncols; int *useless_rows = prob->usefulRowInt_; int nuseless_rows = 0; action *actions = new action [ncols]; int nactions = 0; int numberLook = prob->numberColsToDo_; int iLook; int * look = prob->colsToDo_; bool fixInfeasibility = ((prob->presolveOptions_&0x4000) != 0) ; # if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0 # if PRESOLVE_DEBUG > 0 std::cout << "Entering do_tighten_action::presolve; considering " << numberLook << " rows." << std::endl ; # endif presolve_consistent(prob) ; presolve_links_ok(prob) ; presolve_check_sol(prob) ; presolve_check_nbasic(prob) ; # endif # if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING > 0 int startEmptyRows = 0 ; int startEmptyColumns = 0 ; startEmptyRows = prob->countEmptyRows() ; startEmptyColumns = prob->countEmptyCols() ; # if COIN_PRESOLVE_TUNING > 0 double startTime = 0.0; if (prob->tuning_) startTime = CoinCpuTime() ; # endif # endif // singleton columns are especially likely to be caught here for (iLook=0;iLook<numberLook;iLook++) { int j = look[iLook]; // modify bounds if integer if (integerType[j]) { clo[j] = ceil(clo[j]-1.0e-12); cup[j] = floor(cup[j]+1.0e-12); if (clo[j]>cup[j]&&!fixInfeasibility) { // infeasible prob->status_|= 1; prob->messageHandler()->message(COIN_PRESOLVE_COLINFEAS, prob->messages()) <<j <<clo[j] <<cup[j] <<CoinMessageEol; } } if (dcost[j]==0.0) { int iflag=0; /* 1 - up is towards feasibility, -1 down is towards */ int nonFree=0; // Number of non-free rows CoinBigIndex kcs = mcstrt[j]; CoinBigIndex kce = kcs + hincol[j]; // check constraints for (CoinBigIndex k=kcs; k<kce; ++k) { int i = hrow[k]; double coeff = colels[k]; double rlb = rlo[i]; double rub = rup[i]; if (-1.0e28 < rlb && rub < 1.0e28) { // bounded - we lose iflag=0; break; } else if (-1.0e28 < rlb || rub < 1.0e28) { nonFree++; } PRESOLVEASSERT(fabs(coeff) > ZTOLDP); // see what this particular row says // jflag == 1 ==> up is towards feasibility int jflag = (coeff > 0.0 ? (rub > 1.0e28 ? 1 : -1) : (rlb < -1.0e28 ? 1 : -1)); if (iflag) { // check that it agrees with iflag. if (iflag!=jflag) { iflag=0; break; } } else { // first row -- initialize iflag iflag=jflag; } } // done checking constraints if (!nonFree) iflag=0; // all free anyway if (iflag) { if (iflag==1 && cup[j]<1.0e10) { #if PRESOLVE_DEBUG > 1 printf("TIGHTEN UP: %d\n", j); #endif fix_cols[nfixup_cols++] = j; } else if (iflag==-1&&clo[j]>-1.0e10) { // symmetric case //mpre[j] = PRESOLVE_XUP; #if PRESOLVE_DEBUG > 1 printf("TIGHTEN DOWN: %d\n", j); #endif fix_cols[--nfixdown_cols] = j; } else { #if 0 static int limit; static int which = atoi(getenv("WZ")); if (which == -1) ; else if (limit != which) { limit++; continue; } else limit++; printf("TIGHTEN STATS %d %g %g %d: \n", j, clo[j], cup[j], integerType[j]); double *rowels = prob->rowels_; int *hcol = prob->hcol_; int *mrstrt = prob->mrstrt_; int *hinrow = prob->hinrow_; for (CoinBigIndex k=kcs; k<kce; ++k) { int irow = hrow[k]; CoinBigIndex krs = mrstrt[irow]; CoinBigIndex kre = krs + hinrow[irow]; printf("%d %g %g %g: ", irow, rlo[irow], rup[irow], colels[irow]); for (CoinBigIndex kk=krs; kk<kre; ++kk) printf("%d(%g) ", hcol[kk], rowels[kk]); printf("\n"); } #endif { action *s = &actions[nactions]; nactions++; s->col = j; PRESOLVE_DETAIL_PRINT(printf("pre_tighten %dC E\n",j)); if (integerType[j]) { assert (iflag==-1||iflag==1); iflag *= 2; // say integer } s->direction = iflag; s->rows = new int[hincol[j]]; s->lbound = new double[hincol[j]]; s->ubound = new double[hincol[j]]; #if PRESOLVE_DEBUG > 1 printf("TIGHTEN FREE: %d ", j); #endif int nr = 0; prob->addCol(j); for (CoinBigIndex k=kcs; k<kce; ++k) { int irow = hrow[k]; // ignore this if we've already made it useless if (! (rlo[irow] == -PRESOLVE_INF && rup[irow] == PRESOLVE_INF)) { prob->addRow(irow); s->rows [nr] = irow; s->lbound[nr] = rlo[irow]; s->ubound[nr] = rup[irow]; nr++; useless_rows[nuseless_rows++] = irow; rlo[irow] = -PRESOLVE_INF; rup[irow] = PRESOLVE_INF; #if PRESOLVE_DEBUG > 1 printf("%d ", irow); #endif } } s->nrows = nr; #if PRESOLVE_DEBUG > 1 printf("\n"); #endif } } } } } #if PRESOLVE_SUMMARY > 0 if (nfixdown_cols<ncols || nfixup_cols || nuseless_rows) { printf("NTIGHTENED: %d %d %d\n", ncols-nfixdown_cols, nfixup_cols, nuseless_rows); } #endif if (nuseless_rows) { next = new do_tighten_action(nactions, CoinCopyOfArray(actions,nactions), next); next = useless_constraint_action::presolve(prob, useless_rows, nuseless_rows, next); } deleteAction(actions, action*); //delete[]useless_rows; if (nfixdown_cols<ncols) { int * fixdown_cols = fix_cols+nfixdown_cols; nfixdown_cols = ncols-nfixdown_cols; next = make_fixed_action::presolve(prob, fixdown_cols, nfixdown_cols, true, next); } //delete[]fixdown_cols; if (nfixup_cols) { next = make_fixed_action::presolve(prob, fix_cols, nfixup_cols, false, next); } //delete[]fixup_cols; # if COIN_PRESOLVE_TUNING > 0 if (prob->tuning_) double thisTime = CoinCpuTime() ; # endif # if PRESOLVE_CONSISTENCY > 0 || PRESOLVE_DEBUG > 0 presolve_check_sol(prob) ; # endif # if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING > 0 int droppedRows = prob->countEmptyRows()-startEmptyRows ; int droppedColumns = prob->countEmptyCols()-startEmptyColumns ; std::cout << "Leaving do_tighten_action::presolve, " << droppedRows << " rows, " << droppedColumns << " columns dropped" ; # if COIN_PRESOLVE_TUNING > 0 std::cout << " in " << thisTime-startTime << "s" ; # endif std::cout << "." << std::endl ; # endif return (next); }
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; }
/* * * The col rep and row rep must be consistent. */ const CoinPresolveAction *tripleton_action::presolve(CoinPresolveMatrix *prob, const CoinPresolveAction *next) { double startTime = 0.0; int startEmptyRows=0; int startEmptyColumns = 0; if (prob->tuning_) { startTime = CoinCpuTime(); startEmptyRows = prob->countEmptyRows(); startEmptyColumns = prob->countEmptyCols(); } double *colels = prob->colels_; int *hrow = prob->hrow_; CoinBigIndex *mcstrt = prob->mcstrt_; int *hincol = prob->hincol_; int ncols = prob->ncols_; double *clo = prob->clo_; double *cup = prob->cup_; double *rowels = prob->rowels_; int *hcol = prob->hcol_; CoinBigIndex *mrstrt = prob->mrstrt_; int *hinrow = prob->hinrow_; int nrows = prob->nrows_; double *rlo = prob->rlo_; double *rup = prob->rup_; presolvehlink *clink = prob->clink_; presolvehlink *rlink = prob->rlink_; const unsigned char *integerType = prob->integerType_; double *cost = prob->cost_; int numberLook = prob->numberRowsToDo_; int iLook; int * look = prob->rowsToDo_; const double ztolzb = prob->ztolzb_; action * actions = new action [nrows]; # ifdef ZEROFAULT // initialise alignment padding bytes memset(actions,0,nrows*sizeof(action)) ; # endif int nactions = 0; int *zeros = prob->usefulColumnInt_; //new int[ncols]; char * mark = reinterpret_cast<char *>(zeros+ncols); memset(mark,0,ncols); int nzeros = 0; // If rowstat exists then all do unsigned char *rowstat = prob->rowstat_; double *acts = prob->acts_; // unsigned char * colstat = prob->colstat_; # if PRESOLVE_CONSISTENCY presolve_links_ok(prob) ; # endif // wasfor (int irow=0; irow<nrows; irow++) for (iLook=0;iLook<numberLook;iLook++) { int irow = look[iLook]; if (hinrow[irow] == 3 && fabs(rup[irow] - rlo[irow]) <= ZTOLDP) { double rhs = rlo[irow]; CoinBigIndex krs = mrstrt[irow]; CoinBigIndex kre = krs + hinrow[irow]; int icolx, icoly, icolz; double coeffx, coeffy, coeffz; CoinBigIndex k; /* locate first column */ for (k=krs; k<kre; k++) { if (hincol[hcol[k]] > 0) { break; } } PRESOLVEASSERT(k<kre); coeffx = rowels[k]; if (fabs(coeffx) < ZTOLDP2) continue; icolx = hcol[k]; /* locate second column */ for (k++; k<kre; k++) { if (hincol[hcol[k]] > 0) { break; } } PRESOLVEASSERT(k<kre); coeffy = rowels[k]; if (fabs(coeffy) < ZTOLDP2) continue; icoly = hcol[k]; /* locate third column */ for (k++; k<kre; k++) { if (hincol[hcol[k]] > 0) { break; } } PRESOLVEASSERT(k<kre); coeffz = rowels[k]; if (fabs(coeffz) < ZTOLDP2) continue; icolz = hcol[k]; // For now let's do obvious one if (coeffx*coeffz>0.0) { if(coeffx*coeffy>0.0) continue; } else if (coeffx*coeffy>0.0) { int iTemp = icoly; icoly=icolz; icolz=iTemp; double dTemp = coeffy; coeffy=coeffz; coeffz=dTemp; } else { int iTemp = icoly; icoly=icolx; icolx=iTemp; double dTemp = coeffy; coeffy=coeffx; coeffx=dTemp; } // Not all same sign and y is odd one out // don't bother with fixed variables if (!(fabs(cup[icolx] - clo[icolx]) < ZTOLDP) && !(fabs(cup[icoly] - clo[icolx]) < ZTOLDP) && !(fabs(cup[icolz] - clo[icoly]) < ZTOLDP)) { assert (coeffx*coeffz>0.0&&coeffx*coeffy<0.0); // Only do if does not give implicit bounds on x and z double cx = - coeffx/coeffy; double cz = - coeffz/coeffy; /* don't do if y integer for now */ if (integerType[icoly]) { #define PRESOLVE_DANGEROUS #ifndef PRESOLVE_DANGEROUS continue; #else if (!integerType[icolx]||!integerType[icolz]) continue; if (cx!=floor(cx+0.5)||cz!=floor(cz+0.5)) continue; #endif } double rhsRatio = rhs/coeffy; if (clo[icoly]>-1.0e30) { if (clo[icolx]<-1.0e30||clo[icolz]<-1.0e30) continue; if (cx*clo[icolx]+cz*clo[icolz]+rhsRatio<clo[icoly]-ztolzb) continue; } if (cup[icoly]<1.0e30) { if (cup[icolx]>1.0e30||cup[icolz]>1.0e30) continue; if (cx*cup[icolx]+cz*cup[icolz]+rhsRatio>cup[icoly]+ztolzb) continue; } CoinBigIndex krowx,krowy,krowz; /* find this row in each of the columns and do counts */ bool singleton=false; for (k=mcstrt[icoly]; k<mcstrt[icoly]+hincol[icoly]; k++) { int jrow=hrow[k]; if (hinrow[jrow]==1) singleton=true; if (jrow == irow) krowy=k; else prob->setRowUsed(jrow); } int nDuplicate=0; for (k=mcstrt[icolx]; k<mcstrt[icolx]+hincol[icolx]; k++) { int jrow=hrow[k]; if (jrow == irow) krowx=k; else if (prob->rowUsed(jrow)) nDuplicate++;; } for (k=mcstrt[icolz]; k<mcstrt[icolz]+hincol[icolz]; k++) { int jrow=hrow[k]; if (jrow == irow) krowz=k; else if (prob->rowUsed(jrow)) nDuplicate++;; } int nAdded=hincol[icoly]-3-nDuplicate; for (k=mcstrt[icoly]; k<mcstrt[icoly]+hincol[icoly]; k++) { int jrow=hrow[k]; prob->unsetRowUsed(jrow); } // let singleton rows be taken care of first if (singleton) continue; //if (nAdded<=1) //printf("%d elements added, hincol %d , dups %d\n",nAdded,hincol[icoly],nDuplicate); if (nAdded>2) continue; // it is possible that both x/z and y are singleton columns // that can cause problems if ((hincol[icolx] == 1 ||hincol[icolz] == 1) && hincol[icoly] == 1) continue; // common equations are of the form ax + by = 0, or x + y >= lo { action *s = &actions[nactions]; nactions++; PRESOLVE_DETAIL_PRINT(printf("pre_tripleton %dR %dC %dC %dC E\n", irow,icoly,icolx,icolz)); s->row = irow; s->icolx = icolx; s->icolz = icolz; s->icoly = icoly; s->cloy = clo[icoly]; s->cupy = cup[icoly]; s->costy = cost[icoly]; s->rlo = rlo[irow]; s->rup = rup[irow]; s->coeffx = coeffx; s->coeffy = coeffy; s->coeffz = coeffz; s->ncoly = hincol[icoly]; s->colel = presolve_dupmajor(colels, hrow, hincol[icoly], mcstrt[icoly]); } // costs // the effect of maxmin cancels out cost[icolx] += cost[icoly] * cx; cost[icolz] += cost[icoly] * cz; prob->change_bias(cost[icoly] * rhs / coeffy); //if (cost[icoly]*rhs) //printf("change %g col %d cost %g rhs %g coeff %g\n",cost[icoly]*rhs/coeffy, // icoly,cost[icoly],rhs,coeffy); if (rowstat) { // update solution and basis int numberBasic=0; if (prob->columnIsBasic(icoly)) numberBasic++; if (prob->rowIsBasic(irow)) numberBasic++; if (numberBasic>1) { if (!prob->columnIsBasic(icolx)) prob->setColumnStatus(icolx,CoinPrePostsolveMatrix::basic); else prob->setColumnStatus(icolz,CoinPrePostsolveMatrix::basic); } } // Update next set of actions { prob->addCol(icolx); int i,kcs,kce; kcs = mcstrt[icoly]; kce = kcs + hincol[icoly]; for (i=kcs;i<kce;i++) { int row = hrow[i]; prob->addRow(row); } kcs = mcstrt[icolx]; kce = kcs + hincol[icolx]; for (i=kcs;i<kce;i++) { int row = hrow[i]; prob->addRow(row); } prob->addCol(icolz); kcs = mcstrt[icolz]; kce = kcs + hincol[icolz]; for (i=kcs;i<kce;i++) { int row = hrow[i]; prob->addRow(row); } } /* transfer the colx factors to coly */ bool no_mem = elim_tripleton("ELIMT", mcstrt, rlo, acts, rup, colels, hrow, hcol, hinrow, hincol, clink, ncols, rlink, nrows, mrstrt, rowels, cx, cz, rhs / coeffy, irow, icolx, icoly,icolz); if (no_mem) throwCoinError("out of memory", "tripleton_action::presolve"); // now remove irow from icolx and icolz in the col rep // better if this were first. presolve_delete_from_col(irow,icolx,mcstrt,hincol,hrow,colels) ; presolve_delete_from_col(irow,icolz,mcstrt,hincol,hrow,colels) ; // eliminate irow entirely from the row rep hinrow[irow] = 0; // eliminate irow entirely from the row rep PRESOLVE_REMOVE_LINK(rlink, irow); // eliminate coly entirely from the col rep PRESOLVE_REMOVE_LINK(clink, icoly); cost[icoly] = 0.0; rlo[irow] = 0.0; rup[irow] = 0.0; if (!mark[icolx]) { mark[icolx]=1; zeros[nzeros++]=icolx; } if (!mark[icolz]) { mark[icolz]=1; zeros[nzeros++]=icolz; } } # if PRESOLVE_CONSISTENCY presolve_links_ok(prob) ; presolve_consistent(prob); # endif } } if (nactions) { # if PRESOLVE_SUMMARY printf("NTRIPLETONS: %d\n", nactions); # endif action *actions1 = new action[nactions]; CoinMemcpyN(actions, nactions, actions1); next = new tripleton_action(nactions, actions1, next); if (nzeros) { next = drop_zero_coefficients_action::presolve(prob, zeros, nzeros, next); } } //delete[]zeros; deleteAction(actions,action*); if (prob->tuning_) { double thisTime=CoinCpuTime(); int droppedRows = prob->countEmptyRows() - startEmptyRows ; int droppedColumns = prob->countEmptyCols() - startEmptyColumns; printf("CoinPresolveTripleton(8) - %d rows, %d columns dropped in time %g, total %g\n", droppedRows,droppedColumns,thisTime-startTime,thisTime-prob->startTime_); } return (next); }
/* It is always the case that one of the variables of a doubleton is, or can be made, implied free, but neither will necessarily be a singleton. Since in the case of a doubleton the number of non-zero entries will never increase if one is eliminated, it makes sense to always eliminate them. The col rep and row rep must be consistent. */ const CoinPresolveAction *doubleton_action::presolve (CoinPresolveMatrix *prob, const CoinPresolveAction *next) { # if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0 # if PRESOLVE_DEBUG > 0 std::cout << "Entering doubleton_action::presolve; considering " << prob->numberRowsToDo_ << " rows." << std::endl ; # endif presolve_consistent(prob) ; presolve_links_ok(prob) ; presolve_check_sol(prob) ; presolve_check_nbasic(prob) ; # endif # if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING > 0 int startEmptyRows = 0 ; int startEmptyColumns = 0 ; startEmptyRows = prob->countEmptyRows() ; startEmptyColumns = prob->countEmptyCols() ; # if COIN_PRESOLVE_TUNING > 0 double startTime = 0.0 ; if (prob->tuning_) startTime = CoinCpuTime() ; # endif # endif const int n = prob->ncols_ ; const int m = prob->nrows_ ; /* Unpack column-major and row-major representations, along with rim vectors. */ CoinBigIndex *colStarts = prob->mcstrt_ ; int *colLengths = prob->hincol_ ; double *colCoeffs = prob->colels_ ; int *rowIndices = prob->hrow_ ; presolvehlink *clink = prob->clink_ ; double *clo = prob->clo_ ; double *cup = prob->cup_ ; CoinBigIndex *rowStarts = prob->mrstrt_ ; int *rowLengths = prob->hinrow_ ; double *rowCoeffs = prob->rowels_ ; int *colIndices = prob->hcol_ ; presolvehlink *rlink = prob->rlink_ ; double *rlo = prob->rlo_ ; double *rup = prob->rup_ ; const unsigned char *integerType = prob->integerType_ ; double *cost = prob->cost_ ; int numberLook = prob->numberRowsToDo_ ; int *look = prob->rowsToDo_ ; const double ztolzb = prob->ztolzb_ ; const double ztolzero = 1.0e-12 ; action *actions = new action [m] ; int nactions = 0 ; /* zeros will hold columns that should be groomed to remove explicit zeros when we're finished. fixed will hold columns that have ended up as fixed variables. */ int *zeros = prob->usefulColumnInt_ ; int nzeros = 0 ; int *fixed = zeros+n ; int nfixed = 0 ; unsigned char *rowstat = prob->rowstat_ ; double *acts = prob->acts_ ; double *sol = prob->sol_ ; /* More like `ignore infeasibility'. */ bool fixInfeasibility = ((prob->presolveOptions_&0x4000) != 0) ; /* Open the main loop to scan for doubleton candidates. */ for (int iLook = 0 ; iLook < numberLook ; iLook++) { const int tgtrow = look[iLook] ; /* We need an equality with two coefficients. Avoid isolated constraints, lest both variables vanish. Failure of the assert indicates that the row- and column-major representations are out of sync. */ if ((rowLengths[tgtrow] != 2) || (fabs(rup[tgtrow]-rlo[tgtrow]) > ZTOLDP)) continue ; const CoinBigIndex krs = rowStarts[tgtrow] ; int tgtcolx = colIndices[krs] ; int tgtcoly = colIndices[krs+1] ; PRESOLVEASSERT(colLengths[tgtcolx] > 0 || colLengths[tgtcoly] > 0) ; if (colLengths[tgtcolx] == 1 && colLengths[tgtcoly] == 1) continue ; /* Avoid prohibited columns and fixed columns. Make sure the coefficients are nonzero. JJF - test should allow one to be prohibited as long as you leave that one. I modified earlier code but hope I have got this right. */ if (prob->colProhibited(tgtcolx) && prob->colProhibited(tgtcoly)) continue ; if (fabs(rowCoeffs[krs]) < ZTOLDP2 || fabs(rowCoeffs[krs+1]) < ZTOLDP2) continue ; if ((fabs(cup[tgtcolx]-clo[tgtcolx]) < ZTOLDP) || (fabs(cup[tgtcoly]-clo[tgtcoly]) < ZTOLDP)) continue ; # if PRESOLVE_DEBUG > 2 std::cout << " row " << tgtrow << " colx " << tgtcolx << " coly " << tgtcoly << " passes preliminary eval." << std::endl ; # endif /* Find this row in each column. The indices are not const because we may flip them below, once we decide which column will be eliminated. */ CoinBigIndex krowx = presolve_find_row(tgtrow,colStarts[tgtcolx], colStarts[tgtcolx]+colLengths[tgtcolx],rowIndices) ; double coeffx = colCoeffs[krowx] ; CoinBigIndex krowy = presolve_find_row(tgtrow,colStarts[tgtcoly], colStarts[tgtcoly]+colLengths[tgtcoly],rowIndices) ; double coeffy = colCoeffs[krowy] ; const double rhs = rlo[tgtrow] ; /* Avoid obscuring a requirement for integrality. If only one variable is integer, keep it and substitute for the continuous variable. If both are integer, substitute only for the forms x = k*y (k integral and non-empty intersection on bounds on x) or x = 1-y, where both x and y are binary. flag bits for integerStatus: 0x01: x integer; 0x02: y integer This bit of code works because 0 is continuous, 1 is integer. Make sure that's true. */ assert((integerType[tgtcolx] == 0) || (integerType[tgtcolx] == 1)) ; assert((integerType[tgtcoly] == 0) || (integerType[tgtcoly] == 1)) ; int integerX = integerType[tgtcolx]; int integerY = integerType[tgtcoly]; /* if one prohibited then treat that as integer. This may be pessimistic - but will catch SOS etc */ if (prob->colProhibited2(tgtcolx)) integerX=1; if (prob->colProhibited2(tgtcoly)) integerY=1; int integerStatus = (integerY<<1)|integerX ; if (integerStatus == 3) { int good = 0 ; double rhs2 = rhs ; if (coeffx < 0.0) { coeffx = -coeffx ; rhs2 += 1 ; } if ((cup[tgtcolx] == 1.0) && (clo[tgtcolx] == 0.0) && (fabs(coeffx-1.0) < 1.0e-7) && !prob->colProhibited2(tgtcoly)) good = 1 ; if (coeffy < 0.0) { coeffy = -coeffy ; rhs2 += 1 ; } if ((cup[tgtcoly] == 1.0) && (clo[tgtcoly] == 0.0) && (fabs(coeffy-1.0) < 1.0e-7) && !prob->colProhibited2(tgtcolx)) good |= 2 ; if (!(good == 3 && fabs(rhs2-1.0) < 1.0e-7)) integerStatus = -1 ; /* Not x+y = 1. Try for ax+by = 0 */ if (integerStatus < 0 && rhs == 0.0) { coeffx = colCoeffs[krowx] ; coeffy = colCoeffs[krowy] ; double ratio ; bool swap = false ; if (fabs(coeffx) > fabs(coeffy)) { ratio = coeffx/coeffy ; } else { ratio = coeffy/coeffx ; swap = true ; } ratio = fabs(ratio) ; if (fabs(ratio-floor(ratio+0.5)) < ztolzero) { integerStatus = swap ? 2 : 1 ; } } /* One last try --- just require an integral substitution formula. But ax+by = 0 above is a subset of ax+by = c below and should pass the test below. For that matter, so will x+y = 1. Why separate special cases above? -- lh, 121106 -- */ if (integerStatus < 0) { bool canDo = false ; coeffx = colCoeffs[krowx] ; coeffy = colCoeffs[krowy] ; double ratio ; bool swap = false ; double rhsRatio ; if (fabs(coeffx) > fabs(coeffy)) { ratio = coeffx/coeffy ; rhsRatio = rhs/coeffx ; } else { ratio = coeffy/coeffx ; rhsRatio = rhs/coeffy ; swap = true ; } ratio = fabs(ratio) ; if (fabs(ratio-floor(ratio+0.5)) < ztolzero) { // possible integerStatus = swap ? 2 : 1 ; // but check rhs if (rhsRatio==floor(rhsRatio+0.5)) canDo=true ; } # ifdef COIN_DEVELOP2 if (canDo) printf("Good CoinPresolveDoubleton tgtcolx %d (%g and bounds %g %g) tgtcoly %d (%g and bound %g %g) - rhs %g\n", tgtcolx,colCoeffs[krowx],clo[tgtcolx],cup[tgtcolx], tgtcoly,colCoeffs[krowy],clo[tgtcoly],cup[tgtcoly],rhs) ; else printf("Bad CoinPresolveDoubleton tgtcolx %d (%g) tgtcoly %d (%g) - rhs %g\n", tgtcolx,colCoeffs[krowx],tgtcoly,colCoeffs[krowy],rhs) ; # endif if (!canDo) continue ; } } /* We've resolved integrality concerns. If we concluded that we need to switch the roles of x and y because of integrality, do that now. If both variables are continuous, we may still want to swap for numeric stability. Eliminate the variable with the larger coefficient. */ if (integerStatus == 2) { CoinSwap(tgtcoly,tgtcolx) ; CoinSwap(krowy,krowx) ; } else if (integerStatus == 0) { if (fabs(colCoeffs[krowy]) < fabs(colCoeffs[krowx])) { CoinSwap(tgtcoly,tgtcolx) ; CoinSwap(krowy,krowx) ; } } /* Don't eliminate y just yet if it's entangled in a singleton row (we want to capture that explicit bound in a column bound). */ const CoinBigIndex kcsy = colStarts[tgtcoly] ; const CoinBigIndex kcey = kcsy+colLengths[tgtcoly] ; bool singletonRow = false ; for (CoinBigIndex kcol = kcsy ; kcol < kcey ; kcol++) { if (rowLengths[rowIndices[kcol]] == 1) { singletonRow = true ; break ; } } // skip if y prohibited if (singletonRow || prob->colProhibited2(tgtcoly)) continue ; coeffx = colCoeffs[krowx] ; coeffy = colCoeffs[krowy] ; # if PRESOLVE_DEBUG > 2 std::cout << " doubleton row " << tgtrow << ", keep x(" << tgtcolx << ") elim x(" << tgtcoly << ")." << std::endl ; # endif PRESOLVE_DETAIL_PRINT(printf("pre_doubleton %dC %dC %dR E\n", tgtcoly,tgtcolx,tgtrow)) ; /* Capture the existing columns and other information before we start to modify the constraint system. Save the shorter column. */ action *s = &actions[nactions] ; nactions++ ; s->row = tgtrow ; s->icolx = tgtcolx ; s->clox = clo[tgtcolx] ; s->cupx = cup[tgtcolx] ; s->costx = cost[tgtcolx] ; s->icoly = tgtcoly ; s->costy = cost[tgtcoly] ; s->rlo = rlo[tgtrow] ; s->coeffx = coeffx ; s->coeffy = coeffy ; s->ncolx = colLengths[tgtcolx] ; s->ncoly = colLengths[tgtcoly] ; if (s->ncoly < s->ncolx) { s->colel = presolve_dupmajor(colCoeffs,rowIndices,colLengths[tgtcoly], colStarts[tgtcoly],tgtrow) ; s->ncolx = 0 ; } else { s->colel = presolve_dupmajor(colCoeffs,rowIndices,colLengths[tgtcolx], colStarts[tgtcolx],tgtrow) ; s->ncoly = 0 ; } /* Move finite bound information from y to x, so that y is implied free. a x + b y = c l1 <= x <= u1 l2 <= y <= u2 l2 <= (c - a x) / b <= u2 b/-a > 0 ==> (b l2 - c) / -a <= x <= (b u2 - c) / -a b/-a < 0 ==> (b u2 - c) / -a <= x <= (b l2 - c) / -a */ { double lo1 = -PRESOLVE_INF ; double up1 = PRESOLVE_INF ; if (-PRESOLVE_INF < clo[tgtcoly]) { if (coeffx*coeffy < 0) lo1 = (coeffy*clo[tgtcoly]-rhs)/-coeffx ; else up1 = (coeffy*clo[tgtcoly]-rhs)/-coeffx ; } if (cup[tgtcoly] < PRESOLVE_INF) { if (coeffx*coeffy < 0) up1 = (coeffy*cup[tgtcoly]-rhs)/-coeffx ; else lo1 = (coeffy*cup[tgtcoly]-rhs)/-coeffx ; } /* Don't forget the objective coefficient. costy y = costy ((c - a x) / b) = (costy c)/b + x (costy -a)/b */ cost[tgtcolx] += (cost[tgtcoly]*-coeffx)/coeffy ; prob->change_bias((cost[tgtcoly]*rhs)/coeffy) ; /* The transfer of bounds could make x infeasible. Patch it up if the problem is minor or if the user was so incautious as to instruct us to ignore it. Prefer an integer value if there's one nearby. If there's nothing to be done, break out of the main loop. */ { double lo2 = CoinMax(clo[tgtcolx],lo1) ; double up2 = CoinMin(cup[tgtcolx],up1) ; if (lo2 > up2) { if (lo2 <= up2+prob->feasibilityTolerance_ || fixInfeasibility) { double nearest = floor(lo2+0.5) ; if (fabs(nearest-lo2) < 2.0*prob->feasibilityTolerance_) { lo2 = nearest ; up2 = nearest ; } else { lo2 = up2 ; } } else { prob->status_ |= 1 ; prob->messageHandler()->message(COIN_PRESOLVE_COLINFEAS, prob->messages()) << tgtcolx << lo2 << up2 << CoinMessageEol ; break ; } } # if PRESOLVE_DEBUG > 2 std::cout << " x(" << tgtcolx << ") lb " << clo[tgtcolx] << " --> " << lo2 << ", ub " << cup[tgtcolx] << " --> " << up2 << std::endl ; # endif clo[tgtcolx] = lo2 ; cup[tgtcolx] = up2 ; /* Do we have a solution to maintain? If so, take a stab at it. If x ends up at bound, prefer to set it nonbasic, but if we're short of basic variables after eliminating y and the logical for the row, make it basic. This code will snap the value of x to bound if it's within the primal feasibility tolerance. */ if (rowstat && sol) { int numberBasic = 0 ; double movement = 0 ; if (prob->columnIsBasic(tgtcolx)) numberBasic++ ; if (prob->columnIsBasic(tgtcoly)) numberBasic++ ; if (prob->rowIsBasic(tgtrow)) numberBasic++ ; if (sol[tgtcolx] <= lo2+ztolzb) { movement = lo2-sol[tgtcolx] ; sol[tgtcolx] = lo2 ; prob->setColumnStatus(tgtcolx, CoinPrePostsolveMatrix::atLowerBound) ; } else if (sol[tgtcolx] >= up2-ztolzb) { movement = up2-sol[tgtcolx] ; sol[tgtcolx] = up2 ; prob->setColumnStatus(tgtcolx, CoinPrePostsolveMatrix::atUpperBound) ; } if (numberBasic > 1) prob->setColumnStatus(tgtcolx,CoinPrePostsolveMatrix::basic) ; /* We need to compensate if x was forced to move. Beyond that, even if x didn't move, we've forced y = (c-ax)/b, and that might not have been true before. So even if x didn't move, y may have moved. Note that the constant term c/b is subtracted out as the constraints are modified, so we don't include it when calculating movement for y. */ if (movement) { const CoinBigIndex kkcsx = colStarts[tgtcolx] ; const CoinBigIndex kkcex = kkcsx+colLengths[tgtcolx] ; for (CoinBigIndex kcol = kkcsx ; kcol < kkcex ; kcol++) { int row = rowIndices[kcol] ; if (rowLengths[row]) acts[row] += movement*colCoeffs[kcol] ; } } movement = ((-coeffx*sol[tgtcolx])/coeffy)-sol[tgtcoly] ; if (movement) { const CoinBigIndex kkcsy = colStarts[tgtcoly] ; const CoinBigIndex kkcey = kkcsy+colLengths[tgtcoly] ; for (CoinBigIndex kcol = kkcsy ; kcol < kkcey ; kcol++) { int row = rowIndices[kcol] ; if (rowLengths[row]) acts[row] += movement*colCoeffs[kcol] ; } } } if (lo2 == up2) fixed[nfixed++] = tgtcolx ; } } /* We're done transferring bounds from y to x, and we've patched up the solution if one existed to patch. One last thing to do before we eliminate column y and the doubleton row: put column x and the entangled rows on the lists of columns and rows to look at in the next round of transforms. */ { prob->addCol(tgtcolx) ; const CoinBigIndex kkcsy = colStarts[tgtcoly] ; const CoinBigIndex kkcey = kkcsy+colLengths[tgtcoly] ; for (CoinBigIndex kcol = kkcsy ; kcol < kkcey ; kcol++) { int row = rowIndices[kcol] ; prob->addRow(row) ; } const CoinBigIndex kkcsx = colStarts[tgtcolx] ; const CoinBigIndex kkcex = kkcsx+colLengths[tgtcolx] ; for (CoinBigIndex kcol = kkcsx ; kcol < kkcex ; kcol++) { int row = rowIndices[kcol] ; prob->addRow(row) ; } } /* Empty tgtrow in the column-major matrix. Deleting the coefficient for (tgtrow,tgtcoly) is a bit costly (given that we're about to drop the whole column), but saves the trouble of checking for it in elim_doubleton. */ presolve_delete_from_col(tgtrow,tgtcolx, colStarts,colLengths,rowIndices,colCoeffs) ; presolve_delete_from_col(tgtrow,tgtcoly, colStarts,colLengths,rowIndices,colCoeffs) ; /* Drop tgtrow in the row-major representation: set the length to 0 and reclaim the major vector space in bulk storage. */ rowLengths[tgtrow] = 0 ; PRESOLVE_REMOVE_LINK(rlink,tgtrow) ; /* Transfer the colx factors to coly. This modifies coefficients in column x as it removes coefficients in column y. */ bool no_mem = elim_doubleton("ELIMD", colStarts,rlo,rup,colCoeffs, rowIndices,colIndices,rowLengths,colLengths, clink,n, rowStarts,rowCoeffs, -coeffx/coeffy, rhs/coeffy, tgtrow,tgtcolx,tgtcoly) ; if (no_mem) throwCoinError("out of memory","doubleton_action::presolve") ; /* Eliminate coly entirely from the col rep. We'll want to groom colx to remove explicit zeros. */ colLengths[tgtcoly] = 0 ; PRESOLVE_REMOVE_LINK(clink, tgtcoly) ; cost[tgtcoly] = 0.0 ; rlo[tgtrow] = 0.0 ; rup[tgtrow] = 0.0 ; zeros[nzeros++] = tgtcolx ; # if PRESOLVE_CONSISTENCY > 0 presolve_consistent(prob) ; presolve_links_ok(prob) ; # endif } /* Tidy up the collected actions and clean up explicit zeros and fixed variables. Don't bother unless we're feasible (status of 0). */ if (nactions && !prob->status_) { # if PRESOLVE_SUMMARY > 0 printf("NDOUBLETONS: %d\n", nactions) ; # endif action *actions1 = new action[nactions] ; CoinMemcpyN(actions, nactions, actions1) ; next = new doubleton_action(nactions, actions1, next) ; if (nzeros) next = drop_zero_coefficients_action::presolve(prob, zeros, nzeros, next) ; if (nfixed) next = remove_fixed_action::presolve(prob, fixed, nfixed, next) ; } deleteAction(actions,action*) ; # if COIN_PRESOLVE_TUNING > 0 if (prob->tuning_) double thisTime = CoinCpuTime() ; # endif # if PRESOLVE_CONSISTENCY > 0 || PRESOLVE_DEBUG > 0 presolve_check_sol(prob) ; # endif # if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING > 0 int droppedRows = prob->countEmptyRows()-startEmptyRows ; int droppedColumns = prob->countEmptyCols()-startEmptyColumns ; std::cout << "Leaving doubleton_action::presolve, " << droppedRows << " rows, " << droppedColumns << " columns dropped" ; # if COIN_PRESOLVE_TUNING > 0 std::cout << " in " << thisTime-startTime << "s" ; # endif std::cout << "." << std::endl ; # endif return (next) ; }
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; }
/* It may be the case that the bounds on the variables in a constraint are such that no matter what feasible value the variables take, the constraint cannot be violated. In this case we can drop the constraint as useless. On the other hand, it may be that the only way to satisfy a constraint is to jam all the variables in the constraint to one of their bounds, fixing the variables. This is a forcing constraint, the primary target of this transform. Detection of both useless and forcing constraints requires calculation of bounds on the row activity (often referred to as lhs bounds, from the common form ax <= b). This routine will remember useless constraints as it finds them and invoke useless_constraint_action to deal with them. The transform applied here simply tightens the bounds on the variables. Other transforms will remove the fixed variables, leaving an empty row which is ultimately dropped. A reasonable question to ask is ``If a variable is already fixed, why do we need a record in the postsolve object?'' The answer is that in postsolve we'll be dealing with a column-major representation and we may need to scan the row (see postsolve comments). So it's useful to record all variables in the constraint. On the other hand, it's definitely harmful to ask remove_fixed_action to process a variable more than once (causes problems in remove_fixed_action::postsolve). Original comments: It looks like these checks could be performed in parallel, that is, the tests could be carried out for all rows in parallel, and then the rows deleted and columns tightened afterward. Obviously, this is true for useless rows. By doing it in parallel rather than sequentially, we may miss transformations due to variables that were fixed by forcing constraints, though. Note that both of these operations will cause problems if the variables in question really need to exceed their bounds in order to make the problem feasible. */ const CoinPresolveAction* forcing_constraint_action::presolve (CoinPresolveMatrix *prob, const CoinPresolveAction *next) { # if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING int startEmptyRows = 0 ; int startEmptyColumns = 0 ; startEmptyRows = prob->countEmptyRows() ; startEmptyColumns = prob->countEmptyCols() ; # endif # if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0 # if PRESOLVE_DEBUG > 0 std::cout << "Entering forcing_constraint_action::presolve, considering " << prob->numberRowsToDo_ << " rows." << std::endl ; # endif presolve_check_sol(prob) ; presolve_check_nbasic(prob) ; # endif # if COIN_PRESOLVE_TUNING double startTime = 0.0 ; if (prob->tuning_) { startTime = CoinCpuTime() ; } # endif // Column solution and bounds double *clo = prob->clo_ ; double *cup = prob->cup_ ; double *csol = prob->sol_ ; // Row-major representation const CoinBigIndex *mrstrt = prob->mrstrt_ ; const double *rowels = prob->rowels_ ; const int *hcol = prob->hcol_ ; const int *hinrow = prob->hinrow_ ; const int nrows = prob->nrows_ ; const double *rlo = prob->rlo_ ; const double *rup = prob->rup_ ; const double tol = ZTOLDP ; const double inftol = prob->feasibilityTolerance_ ; // for redundant rows be safe const double inftol2 = 0.01*prob->feasibilityTolerance_ ; const int ncols = prob->ncols_ ; int *fixed_cols = new int[ncols] ; int nfixed_cols = 0 ; action *actions = new action [nrows] ; int nactions = 0 ; int *useless_rows = new int[nrows] ; int nuseless_rows = 0 ; const int numberLook = prob->numberRowsToDo_ ; int *look = prob->rowsToDo_ ; bool fixInfeasibility = ((prob->presolveOptions_&0x4000) != 0) ; /* Open a loop to scan the constraints of interest. There must be variables left in the row. */ for (int iLook = 0 ; iLook < numberLook ; iLook++) { int irow = look[iLook] ; if (hinrow[irow] <= 0) continue ; const CoinBigIndex krs = mrstrt[irow] ; const CoinBigIndex kre = krs+hinrow[irow] ; /* Calculate upper and lower bounds on the row activity based on upper and lower bounds on the variables. If these are finite and incompatible with the given row bounds, we have infeasibility. */ double maxup, maxdown ; implied_row_bounds(rowels,clo,cup,hcol,krs,kre,maxup,maxdown) ; # if PRESOLVE_DEBUG > 2 std::cout << " considering row " << irow << ", rlo " << rlo[irow] << " LB " << maxdown << " UB " << maxup << " rup " << rup[irow] ; # endif /* If the maximum lhs value is less than L(i) or the minimum lhs value is greater than U(i), we're infeasible. */ if (maxup < PRESOLVE_INF && maxup+inftol < rlo[irow] && !fixInfeasibility) { CoinMessageHandler *hdlr = prob->messageHandler() ; prob->status_|= 1 ; hdlr->message(COIN_PRESOLVE_ROWINFEAS,prob->messages()) << irow << rlo[irow] << rup[irow] << CoinMessageEol ; # if PRESOLVE_DEBUG > 2 std::cout << "; infeasible." << std::endl ; # endif break ; } if (-PRESOLVE_INF < maxdown && rup[irow] < maxdown-inftol && !fixInfeasibility) { CoinMessageHandler *hdlr = prob->messageHandler() ; prob->status_|= 1 ; hdlr->message(COIN_PRESOLVE_ROWINFEAS,prob->messages()) << irow << rlo[irow] << rup[irow] << CoinMessageEol ; # if PRESOLVE_DEBUG > 2 std::cout << "; infeasible." << std::endl ; # endif break ; } /* We've dealt with prima facie infeasibility. Now check if the constraint is trivially satisfied. If so, add it to the list of useless rows and move on. The reason we require maxdown and maxup to be finite if the row bound is finite is to guard against some subsequent transform changing a column bound from infinite to finite. Once finite, bounds continue to tighten, so we're safe. */ /* Test changed to use +small tolerance rather than -tolerance as test fails often */ if (((rlo[irow] <= -PRESOLVE_INF) || (-PRESOLVE_INF < maxdown && rlo[irow] <= maxdown+inftol2)) && ((rup[irow] >= PRESOLVE_INF) || (maxup < PRESOLVE_INF && rup[irow] >= maxup-inftol2))) { // check none prohibited if (prob->anyProhibited_) { bool anyProhibited=false; for (int k=krs; k<kre; k++) { int jcol = hcol[k]; if (prob->colProhibited(jcol)) { anyProhibited=true; break; } } if (anyProhibited) continue; // skip row } useless_rows[nuseless_rows++] = irow ; # if PRESOLVE_DEBUG > 2 std::cout << "; useless." << std::endl ; # endif continue ; } /* Is it the case that we can just barely attain L(i) or U(i)? If so, we have a forcing constraint. As explained above, we need maxup and maxdown to be finite in order for the test to be valid. */ const bool tightAtLower = ((maxup < PRESOLVE_INF) && (fabs(rlo[irow]-maxup) < tol)) ; const bool tightAtUpper = ((-PRESOLVE_INF < maxdown) && (fabs(rup[irow]-maxdown) < tol)) ; # if PRESOLVE_DEBUG > 2 if (tightAtLower || tightAtUpper) std::cout << "; forcing." ; std::cout << std::endl ; # endif if (!(tightAtLower || tightAtUpper)) continue ; // check none prohibited if (prob->anyProhibited_) { bool anyProhibited=false; for (int k=krs; k<kre; k++) { int jcol = hcol[k]; if (prob->colProhibited(jcol)) { anyProhibited=true; break; } } if (anyProhibited) continue; // skip row } /* We have a forcing constraint. Get down to the business of fixing the variables at the appropriate bound. We need to remember the original value of the bound we're tightening. Allocate a pair of arrays the size of the row. Load variables fixed at l<j> from the start, variables fixed at u<j> from the end. Add the column to the list of columns to be processed further. */ double *bounds = new double[hinrow[irow]] ; int *rowcols = new int[hinrow[irow]] ; CoinBigIndex lk = krs ; CoinBigIndex uk = kre ; for (CoinBigIndex k = krs ; k < kre ; k++) { const int j = hcol[k] ; const double lj = clo[j] ; const double uj = cup[j] ; const double coeff = rowels[k] ; PRESOLVEASSERT(fabs(coeff) > ZTOLDP) ; /* If maxup is tight at L(i), then we want to force variables x<j> to the bound that produced maxup: u<j> if a<ij> > 0, l<j> if a<ij> < 0. If maxdown is tight at U(i), it'll be just the opposite. */ if (tightAtLower == (coeff > 0.0)) { --uk ; bounds[uk-krs] = lj ; rowcols[uk-krs] = j ; if (csol != 0) { csol[j] = uj ; } clo[j] = uj ; } else { bounds[lk-krs] = uj ; rowcols[lk-krs] = j ; ++lk ; if (csol != 0) { csol[j] = lj ; } cup[j] = lj ; } /* Only add a column to the list of fixed columns the first time it's fixed. */ if (lj != uj) { fixed_cols[nfixed_cols++] = j ; prob->addCol(j) ; } } PRESOLVEASSERT(uk == lk) ; PRESOLVE_DETAIL_PRINT(printf("pre_forcing %dR E\n",irow)) ; # if PRESOLVE_DEBUG > 1 std::cout << "FORCING: row(" << irow << "), " << (kre-krs) << " variables." << std::endl ; # endif /* Done with this row. Remember the changes in a postsolve action. */ action *f = &actions[nactions] ; nactions++ ; f->row = irow ; f->nlo = lk-krs ; f->nup = kre-uk ; f->rowcols = rowcols ; f->bounds = bounds ; } /* Done processing the rows of interest. No sense doing any additional work unless we're feasible. */ if (prob->status_ == 0) { # if PRESOLVE_DEBUG > 0 std::cout << "FORCING: " << nactions << " forcing, " << nuseless_rows << " useless." << std::endl ; # endif /* Trim the actions array to size and create a postsolve object. */ if (nactions) { next = new forcing_constraint_action(nactions, CoinCopyOfArray(actions,nactions),next) ; } /* Hand off the job of dealing with the useless rows to a specialist. */ if (nuseless_rows) { next = useless_constraint_action::presolve(prob, useless_rows,nuseless_rows,next) ; } /* Hand off the job of dealing with the fixed columns to a specialist. Note that there *cannot* be duplicates in this list or we'll get in trouble `unfixing' a column multiple times. The code above now adds a variable to fixed_cols only if it's not already fixed. If that ever changes, the disabled code (sort, unique) will need to be reenabled. */ if (nfixed_cols) { if (false && nfixed_cols > 1) { std::sort(fixed_cols,fixed_cols+nfixed_cols) ; int *end = std::unique(fixed_cols,fixed_cols+nfixed_cols) ; nfixed_cols = static_cast<int>(end-fixed_cols) ; } next = remove_fixed_action::presolve(prob,fixed_cols,nfixed_cols,next) ; } } else { // delete arrays for (int i=0;i<nactions;i++) { deleteAction(actions[i].rowcols,int *) ; deleteAction(actions[i].bounds,double *) ; } } deleteAction(actions,action*) ; delete [] useless_rows ; delete [] fixed_cols ; # if COIN_PRESOLVE_TUNING if (prob->tuning_) double thisTime = CoinCpuTime() ; # endif # if PRESOLVE_DEBUG > 0 || PRESOLVE_CONSISTENCY > 0 presolve_check_sol(prob) ; presolve_check_nbasic(prob) ; # endif # if PRESOLVE_DEBUG > 0 || COIN_PRESOLVE_TUNING int droppedRows = prob->countEmptyRows()-startEmptyRows ; int droppedColumns = prob->countEmptyCols()-startEmptyColumns ; std::cout << "Leaving forcing_constraint_action::presolve: removed " << droppedRows << " rows, " << droppedColumns << " columns" ; # if COIN_PRESOLVE_TUNING > 0 if (prob->tuning_) std::cout << " in " << (thisTime-prob->startTime_) << "s" ; # endif std::cout << "." << std::endl ; # endif return (next) ; }
/************************************************************************ This main program reads in an integer model from an mps file. It then tries to find SOS structure and solves using N-way variables *************************************************************************/ 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(MIPLIB3DIR) mpsFileName = MIPLIB3DIR "/10teams"; #else if (argc < 2) { fprintf(stderr, "Do not know where to find miplib3 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; } int iRow, iColumn; int numberColumns = solver1.getNumCols(); int numberRows = solver1.getNumRows(); // get row copy const CoinPackedMatrix * matrix = solver1.getMatrixByRow(); const double * element = matrix->getElements(); const int * column = matrix->getIndices(); const CoinBigIndex * rowStart = matrix->getVectorStarts(); const int * rowLength = matrix->getVectorLengths(); const double * rowLower = solver1.getRowLower(); const double * rowUpper = solver1.getRowUpper(); const double * columnLower = solver1.getColLower(); // Look for possible SOS int numberSOS=0; int * mark = new int[numberColumns]; CoinFillN(mark,numberColumns,-1); for (iRow=0;iRow<numberRows;iRow++) { if (rowLower[iRow]==1.0&&rowUpper[iRow]==1.0) { bool goodRow=true; for (int j=rowStart[iRow];j<rowStart[iRow]+rowLength[iRow];j++) { int iColumn = column[j]; if (element[j]!=1.0||!solver1.isInteger(iColumn)||mark[iColumn]>=0||columnLower[iColumn]) { goodRow=false; break; } } if (goodRow) { // mark all for (int j=rowStart[iRow];j<rowStart[iRow]+rowLength[iRow];j++) { int iColumn = column[j]; mark[iColumn]=numberSOS; } numberSOS++; } } } std::cout<<numberSOS<<" SOS"<<std::endl; if (!numberSOS) return 0; CbcModel model(solver1); // Do sets and priorities CbcObject ** objects = new CbcObject * [numberSOS]; int numberIntegers = model.numberIntegers(); /* model may not have created objects If none then create */ if (!numberIntegers||!model.numberObjects()) { model.findIntegers(true); numberIntegers = model.numberIntegers(); } int * priority = new int[numberSOS]; // Set SOS priorities high CoinFillN(priority,numberSOS,1); // Set up SOS int * which = new int[numberColumns]; for (int iSOS =0;iSOS<numberSOS;iSOS++) { int n=0; for (iColumn=0;iColumn<numberColumns;iColumn++) { if (mark[iColumn]==iSOS) which[n++]=iColumn; } // NULL uses 0,1,2 .. as weights objects[iSOS]= new CbcNWay(&model,n,which,iSOS); } delete [] mark; delete [] which; model.addObjects(numberSOS,objects); for (iColumn=0;iColumn<numberSOS;iColumn++) delete objects[iColumn]; delete [] objects; model.passInPriorities(priority,true); delete [] priority; // 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 model.solver()->setHintParam(OsiDoReducePrint,true,OsiHintTry); 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(1); double 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; // Print solution - 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; }