virtual int chooseVariable( OsiSolverInterface * solver, OsiBranchingInformation * info, bool fixVariables){ if(numberUnsatisfied_){ int chosen = (int) (floor(CoinDrand48() * (numberUnsatisfied_))); bestObjectIndex_ = list_[chosen]; bestWhichWay_ = solver->object(bestObjectIndex_)->whichWay(); firstForcedObjectIndex_ = -1; firstForcedWhichWay_ =-1; return 0; } else { return 1; } }
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[]) { ClpSimplex model; int status; // Keep names if (argc < 2) { status = model.readMps("small.mps", true); } else { status = model.readMps(argv[1], true); } if (status) exit(10); /* This driver turns a problem into all equalities, solves it and then creates optimal basis. */ // copy of original ClpSimplex model2(model); // And another ClpSimplex model3(model); int originalNumberColumns = model.numberColumns(); int numberRows = model.numberRows(); int * addStarts = new int [numberRows+1]; int * addRow = new int[numberRows]; double * addElement = new double[numberRows]; double * newUpper = new double[numberRows]; double * newLower = new double[numberRows]; double * lower = model2.rowLower(); double * upper = model2.rowUpper(); int iRow; // Simplest is to change all rhs to zero // One should skip E rows but this is simpler coding for (iRow = 0; iRow < numberRows; iRow++) { newUpper[iRow] = upper[iRow]; upper[iRow] = 0.0; newLower[iRow] = lower[iRow]; lower[iRow] = 0.0; addRow[iRow] = iRow; addElement[iRow] = -1.0; addStarts[iRow] = iRow; } addStarts[numberRows] = numberRows; model2.addColumns(numberRows, newLower, newUpper, NULL, addStarts, addRow, addElement); delete [] addStarts; delete [] addRow; delete [] addElement; delete [] newLower; delete [] newUpper; // Modify costs double * randomArray = new double[numberRows]; for (iRow = 0; iRow < numberRows; iRow++) randomArray[iRow] = CoinDrand48(); model2.transposeTimes(1.0, randomArray, model2.objective()); delete [] randomArray; // solve model2.primal(); // first check okay if solution values back memcpy(model.primalColumnSolution(), model2.primalColumnSolution(), originalNumberColumns * sizeof(double)); memcpy(model.primalRowSolution(), model2.primalRowSolution(), numberRows * sizeof(double)); int iColumn; for (iColumn = 0; iColumn < originalNumberColumns; iColumn++) model.setColumnStatus(iColumn, model2.getColumnStatus(iColumn)); for (iRow = 0; iRow < numberRows; iRow++) { if (model2.getRowStatus(iRow) == ClpSimplex::basic) { model.setRowStatus(iRow, ClpSimplex::basic); } else { model.setRowStatus(iRow, model2.getColumnStatus(iRow + originalNumberColumns)); } } model.primal(0); // and now without solution values for (iColumn = 0; iColumn < originalNumberColumns; iColumn++) model3.setColumnStatus(iColumn, model2.getColumnStatus(iColumn)); for (iRow = 0; iRow < numberRows; iRow++) model3.setRowStatus(iRow, model2.getColumnStatus(iRow + originalNumberColumns)); model3.primal(0); return 0; }
/* Randomized Rounding Heuristic Returns 1 if solution, 0 if not */ int CbcHeuristicRandRound::solution(double & solutionValue, double * betterSolution) { // rlh: Todo: Memory Cleanup // std::cout << "Entering the Randomized Rounding Heuristic" << std::endl; setWhen(1); // setWhen(1) didn't have the effect I expected (e.g., run once). // Run only once. // // See if at root node bool atRoot = model_->getNodeCount() == 0; int passNumber = model_->getCurrentPassNumber(); // Just do once if (!atRoot || passNumber > 1) { // std::cout << "Leaving the Randomized Rounding Heuristic" << std::endl; return 0; } std::cout << "Entering the Randomized Rounding Heuristic" << std::endl; typedef struct { int numberSolutions; int maximumSolutions; int numberColumns; double ** solution; int * numberUnsatisfied; } clpSolution; double start = CoinCpuTime(); numCouldRun_++; // #ifdef HEURISTIC_INFORM printf("Entering heuristic %s - nRuns %d numCould %d when %d\n", heuristicName(),numRuns_,numCouldRun_,when_); #endif // Todo: Ask JJHF what "number of times // the heuristic could run" means. OsiSolverInterface * solver = model_->solver()->clone(); double primalTolerance ; solver->getDblParam(OsiPrimalTolerance, primalTolerance) ; OsiClpSolverInterface * clpSolver = dynamic_cast<OsiClpSolverInterface *> (solver); assert (clpSolver); ClpSimplex * simplex = clpSolver->getModelPtr(); // Initialize the structure holding the solutions for the Simplex iterations clpSolution solutions; // Set typeStruct field of ClpTrustedData struct to 1 to indicate // desired behavior for RandRound heuristic (which is what?) ClpTrustedData trustedSolutions; trustedSolutions.typeStruct = 1; trustedSolutions.data = &solutions; solutions.numberSolutions = 0; solutions.maximumSolutions = 0; solutions.numberColumns = simplex->numberColumns(); solutions.solution = NULL; solutions.numberUnsatisfied = NULL; simplex->setTrustedUserPointer(&trustedSolutions); // Solve from all slack to get some points simplex->allSlackBasis(); // Calling primal() invalidates pointers to some rim vectors, // like...row sense (!) simplex->primal(); // 1. Okay - so a workaround would be to copy the data I want BEFORE // calling primal. // 2. Another approach is to ask the simplex solvers NOT to mess up my // rims. // 3. See freeCachedResults() for what is getting // deleted. Everything else points into the structure. // ...or use collower and colupper rather than rowsense. // ..store address of where one of these // Store the basic problem information // -Get the number of columns, rows and rhs vector int numCols = clpSolver->getNumCols(); int numRows = clpSolver->getNumRows(); // Find the integer variables (use columnType(?)) // One if not continuous, that is binary or general integer) // columnType() = 0 continuous // = 1 binary // = 2 general integer bool * varClassInt = new bool[numCols]; const char* columnType = clpSolver->columnType(); int numGenInt = 0; for (int i = 0; i < numCols; i++) { if (clpSolver->isContinuous(i)) varClassInt[i] = 0; else varClassInt[i] = 1; if (columnType[i] == 2) numGenInt++; } // Heuristic is for problems with general integer variables. // If there are none, quit. if (numGenInt++ < 1) { delete [] varClassInt ; std::cout << "Leaving the Randomized Rounding Heuristic" << std::endl; return 0; } // -Get the rows sense const char * rowSense; rowSense = clpSolver->getRowSense(); // -Get the objective coefficients double *originalObjCoeff = CoinCopyOfArray(clpSolver->getObjCoefficients(), numCols); // -Get the matrix of the problem // rlh: look at using sparse representation double ** matrix = new double * [numRows]; for (int i = 0; i < numRows; i++) { matrix[i] = new double[numCols]; for (int j = 0; j < numCols; j++) matrix[i][j] = 0; } const CoinPackedMatrix* matrixByRow = clpSolver->getMatrixByRow(); const double * matrixElements = matrixByRow->getElements(); const int * matrixIndices = matrixByRow->getIndices(); const int * matrixStarts = matrixByRow->getVectorStarts(); for (int j = 0; j < numRows; j++) { for (int i = matrixStarts[j]; i < matrixStarts[j+1]; i++) { matrix[j][matrixIndices[i]] = matrixElements[i]; } } double * newObj = new double [numCols]; srand ( static_cast<unsigned int>(time(NULL) + 1)); int randNum; // Shuffle the rows: // Put the rows in a random order // so that the optimal solution is a different corner point than the // starting point. int * index = new int [numRows]; for (int i = 0; i < numRows; i++) index[i] = i; for (int i = 0; i < numRows; i++) { int temp = index[i]; int randNumTemp = i + intRand(numRows - i); index[i] = index[randNumTemp]; index[randNumTemp] = temp; } // Start finding corner points by iteratively doing the following: // - contruct a randomly tilted objective // - solve for (int i = 0; i < numRows; i++) { // TODO: that 10,000 could be a param in the member data if (solutions.numberSolutions > 10000) break; randNum = intRand(2); for (int j = 0; j < numCols; j++) { // for row i and column j vary the coefficient "a bit" if (randNum == 1) // if the element is zero, then set the new obj // coefficient to 0.1 (i.e., round up) if (fabs(matrix[index[i]][j]) < primalTolerance) newObj[j] = 0.1; else // if the element is nonzero, then increase the new obj // coefficient "a bit" newObj[j] = matrix[index[i]][j] * 1.1; else // if randnum is 2, then // if the element is zero, then set the new obj coeffient // to NEGATIVE 0.1 (i.e., round down) if (fabs(matrix[index[i]][j]) < primalTolerance) newObj[j] = -0.1; else // if the element is nonzero, then DEcrease the new obj coeffienct "a bit" newObj[j] = matrix[index[i]][j] * 0.9; } // Use the new "tilted" objective clpSolver->setObjective(newObj); // Based on the row sense, we decide whether to max or min if (rowSense[i] == 'L') clpSolver->setObjSense(-1); else clpSolver->setObjSense(1); // Solve with primal simplex simplex->primal(1); // rlh+ll: This was the original code. But we already have the // model pointer (it's in simplex). And, calling getModelPtr() // invalidates the cached data in the OsiClpSolverInterface // object, which means our precious rowsens is lost. So let's // not use the line below... /******* clpSolver->getModelPtr()->primal(1); */ printf("---------------------------------------------------------------- %d\n", i); } // Iteratively do this process until... // either you reach the max number of corner points (aka 10K) // or all the rows have been used as an objective. // Look at solutions int numberSolutions = solutions.numberSolutions; //const char * integerInfo = simplex->integerInformation(); //const double * columnLower = simplex->columnLower(); //const double * columnUpper = simplex->columnUpper(); printf("there are %d solutions\n", numberSolutions); // Up to here we have all the corner points // Now we need to do the random walks and roundings double ** cornerPoints = new double * [numberSolutions]; for (int j = 0; j < numberSolutions; j++) cornerPoints[j] = solutions.solution[j]; bool feasibility = 1; // rlh: use some COIN max instead of 1e30 (?) double bestObj = 1e30; std::vector< std::vector <double> > feasibles; int numFeasibles = 0; // Check the feasibility of the corner points int numCornerPoints = numberSolutions; const double * rhs = clpSolver->getRightHandSide(); // rlh: row sense hasn't changed. why a fresh copy? // Delete next line. rowSense = clpSolver->getRowSense(); for (int i = 0; i < numCornerPoints; i++) { //get the objective value for this this point double objValue = 0; for (int k = 0; k < numCols; k++) objValue += cornerPoints[i][k] * originalObjCoeff[k]; if (objValue < bestObj) { // check integer feasibility feasibility = 1; for (int j = 0; j < numCols; j++) { if (varClassInt[j]) { double closest = floor(cornerPoints[i][j] + 0.5); if (fabs(cornerPoints[i][j] - closest) > primalTolerance) { feasibility = 0; break; } } } // check all constraints satisfied if (feasibility) { for (int irow = 0; irow < numRows; irow++) { double lhs = 0; for (int j = 0; j < numCols; j++) { lhs += matrix[irow][j] * cornerPoints[i][j]; } if (rowSense[irow] == 'L' && lhs > rhs[irow] + primalTolerance) { feasibility = 0; break; } if (rowSense[irow] == 'G' && lhs < rhs[irow] - primalTolerance) { feasibility = 0; break; } if (rowSense[irow] == 'E' && (lhs - rhs[irow] > primalTolerance || lhs - rhs[irow] < -primalTolerance)) { feasibility = 0; break; } } } if (feasibility) { numFeasibles++; feasibles.push_back(std::vector <double> (numCols)); for (int k = 0; k < numCols; k++) feasibles[numFeasibles-1][k] = cornerPoints[i][k]; printf("obj: %f\n", objValue); if (objValue < bestObj) bestObj = objValue; } } } int numFeasibleCorners; numFeasibleCorners = numFeasibles; //find the center of gravity of the corner points as the first random point double * rp = new double[numCols]; for (int i = 0; i < numCols; i++) { rp[i] = 0; for (int j = 0; j < numCornerPoints; j++) { rp[i] += cornerPoints[j][i]; } rp[i] = rp[i] / numCornerPoints; } //------------------------------------------- //main loop: // -generate the next random point // -round the random point // -check the feasibility of the random point //------------------------------------------- srand ( static_cast<unsigned int>(time(NULL) + 1)); int numRandomPoints = 0; while (numRandomPoints < 50000) { numRandomPoints++; //generate the next random point int randomIndex = intRand(numCornerPoints); double random = CoinDrand48(); for (int i = 0; i < numCols; i++) { rp[i] = (random * (cornerPoints[randomIndex][i] - rp[i])) + rp[i]; } //CRISP ROUNDING //round the random point just generated double * roundRp = new double[numCols]; for (int i = 0; i < numCols; i++) { roundRp[i] = rp[i]; if (varClassInt[i]) { if (rp[i] >= 0) { if (fmod(rp[i], 1) > 0.5) roundRp[i] = floor(rp[i]) + 1; else roundRp[i] = floor(rp[i]); } else { if (fabs(fmod(rp[i], 1)) > 0.5) roundRp[i] = floor(rp[i]); else roundRp[i] = floor(rp[i]) + 1; } } } //SOFT ROUNDING // Look at original files for the "how to" on soft rounding; // Soft rounding omitted here. //Check the feasibility of the rounded random point // -Check the feasibility // -Get the rows sense rowSense = clpSolver->getRowSense(); rhs = clpSolver->getRightHandSide(); //get the objective value for this feasible point double objValue = 0; for (int i = 0; i < numCols; i++) objValue += roundRp[i] * originalObjCoeff[i]; if (objValue < bestObj) { feasibility = 1; for (int i = 0; i < numRows; i++) { double lhs = 0; for (int j = 0; j < numCols; j++) { lhs += matrix[i][j] * roundRp[j]; } if (rowSense[i] == 'L' && lhs > rhs[i] + primalTolerance) { feasibility = 0; break; } if (rowSense[i] == 'G' && lhs < rhs[i] - primalTolerance) { feasibility = 0; break; } if (rowSense[i] == 'E' && (lhs - rhs[i] > primalTolerance || lhs - rhs[i] < -primalTolerance)) { feasibility = 0; break; } } if (feasibility) { printf("Feasible Found.\n"); printf("%.2f\n", CoinCpuTime() - start); numFeasibles++; feasibles.push_back(std::vector <double> (numCols)); for (int i = 0; i < numCols; i++) feasibles[numFeasibles-1][i] = roundRp[i]; printf("obj: %f\n", objValue); if (objValue < bestObj) bestObj = objValue; } } delete [] roundRp; } printf("Number of Feasible Corners: %d\n", numFeasibleCorners); printf("Number of Feasibles Found: %d\n", numFeasibles); if (numFeasibles > 0) printf("Best Objective: %f\n", bestObj); printf("time: %.2f\n", CoinCpuTime() - start); if (numFeasibles == 0) { // cleanup delete [] varClassInt; for (int i = 0; i < numRows; i++) delete matrix[i]; delete [] matrix; delete [] newObj; delete [] index; for (int i = 0; i < numberSolutions; i++) delete cornerPoints[i]; delete [] cornerPoints; delete [] rp; return 0; } // We found something better solutionValue = bestObj; for (int k = 0; k < numCols; k++) { betterSolution[k] = feasibles[numFeasibles-1][k]; } delete [] varClassInt; for (int i = 0; i < numRows; i++) delete matrix[i]; delete [] matrix; delete [] newObj; delete [] index; for (int i = 0; i < numberSolutions; i++) delete cornerPoints[i]; delete [] cornerPoints; delete [] rp; std::cout << "Leaving the Randomized Rounding Heuristic" << std::endl; return 1; }
static inline int intRand(const int range) { return static_cast<int> (floor(CoinDrand48() * range)); }
void CglOddHole::generateCuts(const OsiRowCutDebugger * /*debugger*/, const CoinPackedMatrix & rowCopy, const double * solution, const double * dj, OsiCuts & cs, const int * suitableRow, const int * fixedColumn, const CglTreeInfo info, bool packed) { CoinPackedMatrix columnCopy = rowCopy; columnCopy.reverseOrdering(); // Get basic problem information int nRows=columnCopy.getNumRows(); int nCols=columnCopy.getNumCols(); const int * column = rowCopy.getIndices(); const CoinBigIndex * rowStart = rowCopy.getVectorStarts(); const int * rowLength = rowCopy.getVectorLengths(); const int * row = columnCopy.getIndices(); const CoinBigIndex * columnStart = columnCopy.getVectorStarts(); const int * columnLength = columnCopy.getVectorLengths(); // we need only look at suitable rows and variables with unsatisfied 0-1 // lookup from true row to compressed matrix int * mrow = new int[nRows]; // lookup from true column to compressed int * lookup = new int[nCols]; // number of columns in compressed matrix int nSmall=0; int i; //do lookup from true sequence to compressed int n=0; for (i=0;i<nRows;i++) { if (suitableRow[i]>0) { mrow[i]=n++; } else { mrow[i]=-1; } } for (i=0;i<nCols;i++) { if (!fixedColumn[i]) { lookup[i]=nSmall++; } else { lookup[i]=-1; } } int nSmall2=2*nSmall; // we don't know how big matrix will be #define MAXELS 50000 int maxels=MAXELS; //How do I do reallocs in C++? // 1.0 - value x(i) - value x(j) for each node pair (or reverse if cover) double * cost = reinterpret_cast<double *> (malloc(maxels*sizeof(double))); // arc i.e. j which can be reached from i int * to= reinterpret_cast<int *> (malloc(maxels*sizeof(int))); //original row for each arc int * rowfound=reinterpret_cast<int *> (malloc(maxels*sizeof(int))); // start of each column int * starts=new int[2*nSmall+1]; starts[0]=0; // useful array for marking if already connected int * mark =new int[nSmall2]; memset(mark,0,nSmall2*sizeof(int)); n=0; //number of elements in matrix for (i=0;i<nCols;i++) { int icol=lookup[i]; if (icol>=0) { // column in compressed matrix int k; double dd=1.0000001-solution[i]; mark[icol]=1; // reallocate if matrix reached size limit if (n+nCols>maxels) { maxels*=2; cost=reinterpret_cast<double *> (realloc(cost,maxels*sizeof(double))); to=reinterpret_cast<int *> (realloc(to,maxels*sizeof(int))); rowfound=reinterpret_cast<int *> (realloc(rowfound,maxels*sizeof(int))); } // get all other connected variables for (k=columnStart[i];k<columnStart[i]+columnLength[i];k++) { int irow=row[k]; int jrow=mrow[irow]; // but only if row in compressed matrix if (jrow>=0) { int j; for (j=rowStart[irow];j<rowStart[irow]+rowLength[irow];j++) { int jcol=column[j]; int kcol=lookup[jcol]; if (kcol>=0&&!mark[kcol]) { cost[n]=dd-solution[jcol]; to[n]=kcol; rowfound[n++]=irow;//original row mark[kcol]=1; } } } } starts[icol+1]=n; // zero out markers for next column mark[icol]=0; for (k=starts[icol];k<starts[icol+1];k++) { int ito=to[k]; if (ito<0||ito>=nSmall) abort(); mark[to[k]]=0; } } } //if cover then change sign - otherwise make sure positive if (packed) { for (i=0;i<n;i++) { if (cost[i]<1.0e-10) { cost[i]=1.0e-10; } } } else { for (i=0;i<n;i++) { cost[i]=-cost[i]; if (cost[i]<1.0e-10) { cost[i]=1.0e-10; } } } // we are going to double size if (2*n>maxels) { maxels=2*n; cost=reinterpret_cast<double *> (realloc(cost,maxels*sizeof(double))); to=reinterpret_cast<int *> (realloc(to,maxels*sizeof(int))); rowfound=reinterpret_cast<int *> (realloc(rowfound,maxels*sizeof(int))); } /* copy and make bipartite*/ for (i=0;i<nSmall;i++) { int k,j=i+nSmall; for (k=starts[i];k<starts[i+1];k++) { int ito=to[k]; to[n]=ito; to[k]=ito+nSmall; cost[n]=cost[k]; rowfound[n++]=rowfound[k];; } starts[j+1]=n; } //random numbers to winnow out duplicate cuts double * check = new double[nCols]; if (info.randomNumberGenerator) { const CoinThreadRandom * randomGenerator = info.randomNumberGenerator; for (i=0;i<nCols;i++) { check[i]=randomGenerator->randomDouble(); } } else { CoinSeedRandom(13579); for (i=0;i<nCols;i++) { check[i]=CoinDrand48(); // NOT on a thread by thread basis } } // Shortest path algorithm from Dijkstra - is there a better one? typedef struct { double cost; //cost to starting node int back; //previous node } Path; typedef struct { double cost; //cost to starting node int node; //node } Item; Item * stack = new Item [nSmall2]; Path * path = new Path [nSmall2]; // arrays below are used only if looks promising // allocate here // we don't know how many cuts will be generated int ncuts=0; int maxcuts=1000; double * hash = reinterpret_cast<double *> (malloc(maxcuts*sizeof(double))); // to clean (should not be needed) int * clean = new int[nSmall2]; int * candidate = new int[CoinMax(nSmall2,nCols)]; double * element = new double[nCols]; // in case we want to sort double_double_int_triple * sortit = new double_double_int_triple [nCols]; memset(mark,0,nSmall2*sizeof(int)); int * countcol = new int[nCols]; memset(countcol,0,nCols*sizeof(int)); int bias = packed ? 0 : 1; //amount to add before halving // If nSmall large then should do a randomized subset // Improvement 1 int icol; for (icol=0;icol<nSmall;icol++) { int j; int jcol=icol+nSmall; int istack=1; for (j=0;j<nSmall2;j++) { path[j].cost=1.0e70; path[j].back=nSmall2+1; } path[icol].cost=0.0; path[icol].back=-1; stack[0].cost=0.0; stack[0].node=icol; mark[icol]=1; while(istack) { Item thisItem=stack[--istack]; double thisCost=thisItem.cost; int inode=thisItem.node; int k; mark[inode]=0; //say available for further work // See if sorting every so many would help (and which way)? // Improvement 2 for (k=starts[inode];k<starts[inode+1];k++) { int jnode=to[k]; if (!mark[jnode]&&thisCost+cost[k]<path[jnode].cost-1.0e-12) { path[jnode].cost=thisCost+cost[k]; path[jnode].back=inode; // add to stack stack[istack].cost=path[jnode].cost; stack[istack++].node=jnode; mark[jnode]=1; #ifdef CGL_DEBUG assert (istack<=nSmall2); #endif } } } bool good=(path[jcol].cost<0.9999); if (good) { /* try */ int ii; int nrow2=0; int nclean=0; double sum=0; #ifdef CGL_DEBUG printf("** %d ",jcol-nSmall); #endif ii=1; candidate[0]=jcol; while(jcol!=icol) { int jjcol; jcol=path[jcol].back; if (jcol>=nSmall) { jjcol=jcol-nSmall; } else { jjcol=jcol; } #ifdef CGL_DEBUG printf(" %d",jjcol); #endif if (mark[jjcol]) { // good=false; // probably means this is from another cycle (will have been found) // one of cycles must be zero cost // printf("variable already on chain!\n"); } else { mark[jjcol]=1; clean[nclean++]=jjcol; candidate[ii++]=jcol; #ifdef CGL_DEBUG assert (ii<=nSmall2); #endif } } #ifdef CGL_DEBUG printf("\n"); #endif for (j=0;j<nclean;j++) { int k=clean[j]; mark[k]=0; } if (good) { int k; for (k=ii-1;k>0;k--) { int jk,kk=candidate[k]; int ix=0; for (jk=starts[kk];jk<starts[kk+1];jk++) { int ito=to[jk]; if (ito==candidate[k-1]) { ix=1; // back to original row mrow[nrow2++]=rowfound[jk]; break; } } if (!ix) { good=false; } } if ((nrow2&1)!=1) { good=false; } if (good) { int nincut=0; for (k=0;k<nrow2;k++) { int j,irow=mrow[k]; for (j=rowStart[irow];j<rowStart[irow]+rowLength[irow];j++) { int icol=column[j]; if (!countcol[icol]) candidate[nincut++]=icol; countcol[icol]++; } } #ifdef CGL_DEBUG printf("true constraint %d",nrow2); #endif nrow2=nrow2>>1; double rhs=nrow2; if (!packed) rhs++; // +1 for cover ii=0; for (k=0;k<nincut;k++) { int jcol=candidate[k]; if (countcol[jcol]) { #ifdef CGL_DEBUG printf(" %d %d",jcol,countcol[jcol]); #endif int ihalf=(countcol[jcol]+bias)>>1; if (ihalf) { element[ii]=ihalf; sum+=solution[jcol]*element[ii]; /*printf("%d %g %g\n",jcol,element[ii],sumall[jcol]);*/ candidate[ii++]=jcol; } countcol[jcol]=0; } } #ifdef CGL_DEBUG printf("\n"); #endif OsiRowCut rc; double violation=0.0; if (packed) { violation = sum-rhs; rc.setLb(-COIN_DBL_MAX); rc.setUb(rhs); } else { // other way for cover violation = rhs-sum; rc.setUb(COIN_DBL_MAX); rc.setLb(rhs); } if (violation<minimumViolation_) { #ifdef CGL_DEBUG printf("why no cut\n"); #endif good=false; } else { if (static_cast<double> (ii) * minimumViolationPer_>violation|| ii>maximumEntries_) { #ifdef CGL_DEBUG printf("why no cut\n"); #endif if (packed) { // sort and see if we can get down to length // relax by taking out ones with solution 0.0 nincut=ii; for (k=0;k<nincut;k++) { int jcol=candidate[k]; double value = fabs(dj[jcol]); if (solution[jcol]) value = -solution[jcol]; sortit[k].dj=value; sortit[k].element=element[k]; sortit[k].sequence=jcol; } // sort std::sort(sortit,sortit+nincut,double_double_int_triple_compare()); nincut = CoinMin(nincut,maximumEntries_); sum=0.0; for (k=0;k<nincut;k++) { int jcol=sortit[k].sequence; candidate[k]=jcol; element[k]=sortit[k].element; sum+=solution[jcol]*element[k]; } violation = sum-rhs; ii=nincut; if (violation<minimumViolation_) { good=false; } } else { good=false; } } } if (good) { //this assumes not many cuts int j; #if 0 double value=0.0; for (j=0;j<ii;j++) { int icol=candidate[j]; value += check[icol]*element[j]; } #else CoinPackedVector candidatePv(ii,candidate,element); candidatePv.sortIncrIndex(); double value = candidatePv.dotProduct(check); #endif for (j=0;j<ncuts;j++) { if (value==hash[j]) { //could check equality - quicker just to assume break; } } if (j==ncuts) { //new if (ncuts==maxcuts) { maxcuts *= 2; hash = reinterpret_cast<double *> (realloc(hash,maxcuts*sizeof(double))); } hash[ncuts++]=value; rc.setRow(ii,candidate,element); #ifdef CGL_DEBUG printf("sum %g rhs %g %d\n",sum,rhs,ii); if (debugger) assert(!debugger->invalidCut(rc)); #endif cs.insert(rc); } } } /* end of adding cut */ } } } delete [] countcol; delete [] element; delete [] candidate; delete [] sortit; delete [] clean; delete [] path; delete [] stack; free(hash); delete [] check; delete [] mark; delete [] starts; delete [] lookup; delete [] mrow; free(rowfound); free(to); free(cost); }
//-------------------------------------------------------------------------- // Test building a model void CoinModelUnitTest(const std::string & mpsDir, const std::string & netlibDir, const std::string & testModel) { // Get a model CoinMpsIO m; std::string fn = mpsDir+"exmip1"; int numErr = m.readMps(fn.c_str(),"mps"); assert( numErr== 0 ); int numberRows = m.getNumRows(); int numberColumns = m.getNumCols(); // Build by row from scratch { CoinPackedMatrix matrixByRow = * m.getMatrixByRow(); const double * element = matrixByRow.getElements(); const int * column = matrixByRow.getIndices(); const CoinBigIndex * rowStart = matrixByRow.getVectorStarts(); const int * rowLength = matrixByRow.getVectorLengths(); const double * rowLower = m.getRowLower(); const double * rowUpper = m.getRowUpper(); const double * columnLower = m.getColLower(); const double * columnUpper = m.getColUpper(); const double * objective = m.getObjCoefficients(); int i; CoinModel temp; for (i=0; i<numberRows; i++) { temp.addRow(rowLength[i],column+rowStart[i], element+rowStart[i],rowLower[i],rowUpper[i],m.rowName(i)); } // Now do column part for (i=0; i<numberColumns; i++) { temp.setColumnBounds(i,columnLower[i],columnUpper[i]); temp.setColumnObjective(i,objective[i]); if (m.isInteger(i)) temp.setColumnIsInteger(i,true);; } // write out temp.writeMps("byRow.mps"); } // Build by column from scratch and save CoinModel model; { CoinPackedMatrix matrixByColumn = * m.getMatrixByCol(); const double * element = matrixByColumn.getElements(); const int * row = matrixByColumn.getIndices(); const CoinBigIndex * columnStart = matrixByColumn.getVectorStarts(); const int * columnLength = matrixByColumn.getVectorLengths(); const double * rowLower = m.getRowLower(); const double * rowUpper = m.getRowUpper(); const double * columnLower = m.getColLower(); const double * columnUpper = m.getColUpper(); const double * objective = m.getObjCoefficients(); int i; for (i=0; i<numberColumns; i++) { model.addColumn(columnLength[i],row+columnStart[i], element+columnStart[i],columnLower[i],columnUpper[i], objective[i],m.columnName(i),m.isInteger(i)); } // Now do row part for (i=0; i<numberRows; i++) { model.setRowBounds(i,rowLower[i],rowUpper[i]); } // write out model.writeMps("byColumn.mps"); } // model was created by column - play around { CoinModel temp; int i; for (i=numberRows-1; i>=0; i--) temp.setRowLower(i,model.getRowLower(i)); for (i=0; i<numberColumns; i++) { temp.setColumnUpper(i,model.getColumnUpper(i)); temp.setColumnName(i,model.getColumnName(i)); } for (i=numberColumns-1; i>=0; i--) { temp.setColumnLower(i,model.getColumnLower(i)); temp.setColumnObjective(i,model.getColumnObjective(i)); temp.setColumnIsInteger(i,model.getColumnIsInteger(i)); } for (i=0; i<numberRows; i++) { temp.setRowUpper(i,model.getRowUpper(i)); temp.setRowName(i,model.getRowName(i)); } // Now elements for (i=0; i<numberRows; i++) { CoinModelLink triple=model.firstInRow(i); while (triple.column()>=0) { temp(i,triple.column(),triple.value()); triple=model.next(triple); } } // and by column for (i=numberColumns-1; i>=0; i--) { CoinModelLink triple=model.lastInColumn(i); while (triple.row()>=0) { assert (triple.value()==temp(triple.row(),i)); temp(triple.row(),i,triple.value()); triple=model.previous(triple); } } // check equal model.setLogLevel(1); assert (!model.differentModel(temp,false)); } // Try creating model with strings { CoinModel temp; int i; for (i=numberRows-1; i>=0; i--) { double value = model.getRowLower(i); if (value==-1.0) temp.setRowLower(i,"minusOne"); else if (value==1.0) temp.setRowLower(i,"sqrt(plusOne)"); else if (value==4.0) temp.setRowLower(i,"abs(4*plusOne)"); else temp.setRowLower(i,value); } for (i=0; i<numberColumns; i++) { double value; value = model.getColumnUpper(i); if (value==-1.0) temp.setColumnUpper(i,"minusOne"); else if (value==1.0) temp.setColumnUpper(i,"plusOne"); else temp.setColumnUpper(i,value); temp.setColumnName(i,model.getColumnName(i)); } for (i=numberColumns-1; i>=0; i--) { temp.setColumnLower(i,model.getColumnLower(i)); temp.setColumnObjective(i,model.getColumnObjective(i)); temp.setColumnIsInteger(i,model.getColumnIsInteger(i)); } for (i=0; i<numberRows; i++) { double value = model.getRowUpper(i); if (value==-1.0) temp.setRowUpper(i,"minusOne"); else if (value==1.0) temp.setRowUpper(i,"plusOne"); else temp.setRowUpper(i,value); temp.setRowName(i,model.getRowName(i)); } // Now elements for (i=0; i<numberRows; i++) { CoinModelLink triple=model.firstInRow(i); while (triple.column()>=0) { double value = triple.value(); if (value==-1.0) temp(i,triple.column(),"minusOne"); else if (value==1.0) temp(i,triple.column(),"plusOne"); else if (value==-2.0) temp(i,triple.column(),"minusOne-1.0"); else if (value==2.0) temp(i,triple.column(),"plusOne+1.0+minusOne+(2.0-plusOne)"); else temp(i,triple.column(),value); triple=model.next(triple); } } temp.associateElement("minusOne",-1.0); temp.associateElement("plusOne",1.0); temp.setProblemName("fromStrings"); temp.writeMps("string.mps"); // check equal model.setLogLevel(1); assert (!model.differentModel(temp,false)); } // Test with various ways of generating { /* Get a model. Try first with netlibDir, fall back to mpsDir (sampleDir) if that fails. */ CoinMpsIO m; std::string fn = netlibDir+testModel; double time1 = CoinCpuTime(); int numErr = m.readMps(fn.c_str(),""); if (numErr != 0) { std::cout << "Could not read " << testModel << " in " << netlibDir << "; falling back to " << mpsDir << "." << std::endl ; fn = mpsDir+testModel ; numErr = m.readMps(fn.c_str(),"") ; if (numErr != 0) { std::cout << "Could not read " << testModel << "; skipping test." << std::endl ; } } if (numErr == 0) { std::cout << "Time for readMps is " << (CoinCpuTime()-time1) << " seconds." << std::endl ; int numberRows = m.getNumRows(); int numberColumns = m.getNumCols(); // Build model CoinModel model; CoinPackedMatrix matrixByRow = * m.getMatrixByRow(); const double * element = matrixByRow.getElements(); const int * column = matrixByRow.getIndices(); const CoinBigIndex * rowStart = matrixByRow.getVectorStarts(); const int * rowLength = matrixByRow.getVectorLengths(); const double * rowLower = m.getRowLower(); const double * rowUpper = m.getRowUpper(); const double * columnLower = m.getColLower(); const double * columnUpper = m.getColUpper(); const double * objective = m.getObjCoefficients(); int i; for (i=0; i<numberRows; i++) { model.addRow(rowLength[i],column+rowStart[i], element+rowStart[i],rowLower[i],rowUpper[i],m.rowName(i)); } // Now do column part for (i=0; i<numberColumns; i++) { model.setColumnBounds(i,columnLower[i],columnUpper[i]); model.setColumnObjective(i,objective[i]); model.setColumnName(i,m.columnName(i)); if (m.isInteger(i)) model.setColumnIsInteger(i,true);; } // Test CoinSeedRandom(11111); time1 = 0.0; int nPass=50; for (i=0; i<nPass; i++) { double random = CoinDrand48(); int iSeed = (int) (random*1000000); //iSeed = 776151; CoinSeedRandom(iSeed); std::cout << "before pass " << i << " with seed of " << iSeed << std::endl ; buildRandom(model,CoinDrand48(),time1,i); model.validateLinks(); } std::cout << "Time for " << nPass << " CoinModel passes is " << time1 << " seconds\n" << std::endl ; } } }
/* Build a model in some interesting way Nine blocks defined by 4 random numbers If next random number <0.4 addRow next possible If <0.8 addColumn if possible Otherwise do by element For each one use random <0.5 to add rim at same time At end fill in rim at random */ void buildRandom(CoinModel & baseModel, double random, double & timeIt, int iPass) { CoinModel model; int numberRows = baseModel.numberRows(); int numberColumns = baseModel.numberColumns(); int numberElements = baseModel.numberElements(); // Row numbers and column numbers int lastRow[4]; int lastColumn[4]; int i; lastRow[0]=0; lastColumn[0]=0; lastRow[3]=numberRows; lastColumn[3]=numberColumns; for ( i=1; i<3; i++) { int size; size = (int) ((0.25*random+0.2)*numberRows); random = CoinDrand48(); lastRow[i]=lastRow[i-1]+size; size = (int) ((0.25*random+0.2)*numberColumns); random = CoinDrand48(); lastColumn[i]=lastColumn[i-1]+size; } // whether block done 0 row first char block[9]= {0,0,0,0,0,0,0,0,0}; // whether rowRim done char rowDone[3]= {0,0,0}; // whether columnRim done char columnDone[3]= {0,0,0}; // Save array for deleting elements CoinModelTriple * dTriple = new CoinModelTriple[numberElements]; numberElements=0; double time1 = CoinCpuTime(); for (int jBlock=0; jBlock<9; jBlock++) { int iType=-1; int iBlock=-1; if (random<0.4) { // trying addRow int j; for (j=0; j<3; j++) { int k; for (k=0; k<3; k++) { if (block[3*j+k]) break; //already taken } if (k==3) { // can do but decide which one iBlock = 3*j + (int) (CoinDrand48()*0.3); iType=0; break; } } } if (iType==-1&&random<0.8) { // trying addRow int j; for (j=0; j<3; j++) { int k; for (k=0; k<3; k++) { if (block[j+3*k]) break; //already taken } if (k==3) { // can do but decide which one iBlock = j + 3*((int) (CoinDrand48()*0.3)); iType=1; break; } } } if (iType==-1) { iType=2; int j; for (j=0; j<9; j++) { if (!block[j]) { iBlock=j; break; } } } random=CoinDrand48(); assert (iBlock>=0&&iBlock<9); assert (iType>=0); assert (!block[iBlock]); block[iBlock]=static_cast<char>(1+iType); int jRow = iBlock/3; int jColumn = iBlock%3; bool doRow = (CoinDrand48()<0.5)&&!rowDone[jRow]; bool doColumn = (CoinDrand48()<0.5&&!columnDone[jColumn]); if (!iType) { // addRow int * column = new int[lastColumn[jColumn+1]-lastColumn[jColumn]]; double * element = new double[lastColumn[jColumn+1]-lastColumn[jColumn]]; for (i=lastRow[jRow]; i<lastRow[jRow+1]; i++) { int n=0; CoinModelLink triple=baseModel.firstInRow(i); while (triple.column()>=0) { if (triple.column()>=lastColumn[jColumn]&&triple.column()<lastColumn[jColumn+1]) { column[n]=triple.column(); element[n++]=triple.value(); } triple=baseModel.next(triple); } assert (i>=model.numberRows()); if (i>model.numberRows()) { assert (i==lastRow[jRow]); std::cout << "need to fill in rows" << std::endl ; for (int k=0; k<jRow; k++) { int start = CoinMax(lastRow[k],model.numberRows()); int end = lastRow[k+1]; bool doBounds = rowDone[k]!=0; for (int j=start; j<end; j++) { if (doBounds) model.addRow(0,NULL,NULL,baseModel.rowLower(j), baseModel.rowUpper(j),baseModel.rowName(j)); else model.addRow(0,NULL,NULL); } } } if (doRow) model.addRow(n,column,element,baseModel.rowLower(i), baseModel.rowUpper(i),baseModel.rowName(i)); else model.addRow(n,column,element); } if (doRow) { rowDone[jRow]=1; } delete [] column; delete [] element; } else if (iType==1) { // addColumn int * row = new int[lastRow[jRow+1]-lastRow[jRow]]; double * element = new double[lastRow[jRow+1]-lastRow[jRow]]; for (i=lastColumn[jColumn]; i<lastColumn[jColumn+1]; i++) { int n=0; CoinModelLink triple=baseModel.firstInColumn(i); while (triple.row()>=0) { if (triple.row()>=lastRow[jRow]&&triple.row()<lastRow[jRow+1]) { row[n]=triple.row(); element[n++]=triple.value(); } triple=baseModel.next(triple); } assert (i>=model.numberColumns()); if (i>model.numberColumns()) { assert (i==lastColumn[jColumn]); std::cout << "need to fill in columns" << std::endl ; for (int k=0; k<jColumn; k++) { int start = CoinMax(lastColumn[k],model.numberColumns()); int end = lastColumn[k+1]; bool doBounds = columnDone[k]!=0; for (int j=start; j<end; j++) { if (doBounds) model.addColumn(0,NULL,NULL,baseModel.columnLower(j), baseModel.columnUpper(j),baseModel.objective(j), baseModel.columnName(j),baseModel.isInteger(j)); else model.addColumn(0,NULL,NULL); } } } if (doColumn) model.addColumn(n,row,element,baseModel.columnLower(i), baseModel.columnUpper(i),baseModel.objective(i), baseModel.columnName(i),baseModel.isInteger(i)); else model.addColumn(n,row,element); } if (doColumn) { columnDone[jColumn]=1; } delete [] row; delete [] element; } else { // addElement // Which way round ? if (CoinDrand48()<0.5) { // rim first if (doRow) { for (i=lastRow[jRow]; i<lastRow[jRow+1]; i++) { model.setRowLower(i,baseModel.getRowLower(i)); model.setRowUpper(i,baseModel.getRowUpper(i)); model.setRowName(i,baseModel.getRowName(i)); } rowDone[jRow]=1; } if (doColumn) { for (i=lastColumn[jColumn]; i<lastColumn[jColumn+1]; i++) { model.setColumnLower(i,baseModel.getColumnLower(i)); model.setColumnUpper(i,baseModel.getColumnUpper(i)); model.setColumnName(i,baseModel.getColumnName(i)); model.setColumnObjective(i,baseModel.getColumnObjective(i)); model.setColumnIsInteger(i,baseModel.getColumnIsInteger(i)); } columnDone[jColumn]=1; } if (CoinDrand48()<0.3) { // by row for (i=lastRow[jRow]; i<lastRow[jRow+1]; i++) { CoinModelLink triple=baseModel.firstInRow(i); while (triple.column()>=0) { int iColumn = triple.column(); if (iColumn>=lastColumn[jColumn]&&iColumn<lastColumn[jColumn+1]) model(i,triple.column(),triple.value()); triple=baseModel.next(triple); } } } else if (CoinDrand48()<0.6) { // by column for (i=lastColumn[jColumn]; i<lastColumn[jColumn+1]; i++) { CoinModelLink triple=baseModel.firstInColumn(i); while (triple.row()>=0) { int iRow = triple.row(); if (iRow>=lastRow[jRow]&&iRow<lastRow[jRow+1]) model(triple.row(),i,triple.value()); triple=baseModel.next(triple); } } } else { // scan through backwards const CoinModelTriple * elements = baseModel.elements(); for (i=baseModel.numberElements()-1; i>=0; i--) { int iRow = (int) rowInTriple(elements[i]); int iColumn = elements[i].column; if (iRow>=lastRow[jRow]&&iRow<lastRow[jRow+1]&& iColumn>=lastColumn[jColumn]&&iColumn<lastColumn[jColumn+1]) model(iRow,iColumn,elements[i].value); } } } else { // elements first if (CoinDrand48()<0.3) { // by row for (i=lastRow[jRow]; i<lastRow[jRow+1]; i++) { CoinModelLink triple=baseModel.firstInRow(i); while (triple.column()>=0) { int iColumn = triple.column(); if (iColumn>=lastColumn[jColumn]&&iColumn<lastColumn[jColumn+1]) model(i,triple.column(),triple.value()); triple=baseModel.next(triple); } } } else if (CoinDrand48()<0.6) { // by column for (i=lastColumn[jColumn]; i<lastColumn[jColumn+1]; i++) { CoinModelLink triple=baseModel.firstInColumn(i); while (triple.row()>=0) { int iRow = triple.row(); if (iRow>=lastRow[jRow]&&iRow<lastRow[jRow+1]) model(triple.row(),i,triple.value()); triple=baseModel.next(triple); } } } else { // scan through backwards const CoinModelTriple * elements = baseModel.elements(); for (i=baseModel.numberElements()-1; i>=0; i--) { int iRow = (int) rowInTriple(elements[i]); int iColumn = elements[i].column; if (iRow>=lastRow[jRow]&&iRow<lastRow[jRow+1]&& iColumn>=lastColumn[jColumn]&&iColumn<lastColumn[jColumn+1]) model(iRow,iColumn,elements[i].value); } } if (doRow) { for (i=lastRow[jRow]; i<lastRow[jRow+1]; i++) { model.setRowLower(i,baseModel.getRowLower(i)); model.setRowUpper(i,baseModel.getRowUpper(i)); model.setRowName(i,baseModel.getRowName(i)); } rowDone[jRow]=1; } if (doColumn) { for (i=lastColumn[jColumn]; i<lastColumn[jColumn+1]; i++) { model.setColumnLower(i,baseModel.getColumnLower(i)); model.setColumnUpper(i,baseModel.getColumnUpper(i)); model.setColumnName(i,baseModel.getColumnName(i)); model.setColumnObjective(i,baseModel.getColumnObjective(i)); model.setColumnIsInteger(i,baseModel.getColumnIsInteger(i)); } columnDone[jColumn]=1; } } } // Mess up be deleting some elements if (CoinDrand48()<0.3&&iPass>10) { double random2=CoinDrand48(); double randomDelete = 0.2 + 0.5*random2; // fraction to delete //model.validateLinks(); if (random2<0.2) { // delete some rows for (int j=lastRow[jRow]; j<lastRow[jRow+1]; j++) { //model.validateLinks(); if (CoinDrand48()<randomDelete) { // save and delete double rowLower = model.rowLower(j); double rowUpper = model.rowUpper(j); char * rowName = CoinStrdup(model.rowName(j)); CoinModelLink triple=model.firstInRow(j); while (triple.column()>=0) { int iColumn = triple.column(); assert (j==triple.row()); setRowInTriple(dTriple[numberElements],j); dTriple[numberElements].column=iColumn; dTriple[numberElements].value = triple.value(); numberElements++; triple=model.next(triple); } model.deleteRow(j); if (rowDone[jRow]) { // put back rim model.setRowLower(j,rowLower); model.setRowUpper(j,rowUpper); model.setRowName(j,rowName); } free(rowName); } } } else if (random2<0.4) { // delete some columns for (int j=lastColumn[jColumn]; j<lastColumn[jColumn+1]; j++) { //model.validateLinks(); if (CoinDrand48()<randomDelete) { // save and delete double columnLower = model.columnLower(j); double columnUpper = model.columnUpper(j); double objective = model.objective(j); bool integer = model.isInteger(j)!=0; char * columnName = CoinStrdup(model.columnName(j)); CoinModelLink triple=model.firstInColumn(j); while (triple.column()>=0) { int iRow = triple.row(); assert (j==triple.column()); dTriple[numberElements].column = j; setRowInTriple(dTriple[numberElements],iRow); dTriple[numberElements].value = triple.value(); numberElements++; triple=model.next(triple); } model.deleteColumn(j); if (columnDone[jColumn]) { // put back rim model.setColumnLower(j,columnLower); model.setColumnUpper(j,columnUpper); model.setObjective(j,objective); model.setIsInteger(j,integer); model.setColumnName(j,columnName); } free(columnName); } } } else { // delete some elements //model.validateLinks(); const CoinModelTriple * elements = baseModel.elements(); for (i=0; i<model.numberElements(); i++) { int iRow = (int) rowInTriple(elements[i]); int iColumn = elements[i].column; if (iRow>=lastRow[jRow]&&iRow<lastRow[jRow+1]&& iColumn>=lastColumn[jColumn]&&iColumn<lastColumn[jColumn+1]) { if (CoinDrand48()<randomDelete) { dTriple[numberElements].column = iColumn; setRowInTriple(dTriple[numberElements],iRow); dTriple[numberElements].value = elements[i].value; int position = model.deleteElement(iRow,iColumn); if (position>=0) numberElements++; } } } } } } // Do rim if necessary for (int k=0; k<3; k++) { if (!rowDone[k]) { for (i=lastRow[k]; i<lastRow[k+1]; i++) { model.setRowLower(i,baseModel.getRowLower(i)); model.setRowUpper(i,baseModel.getRowUpper(i)); model.setRowName(i,baseModel.getRowName(i)); } } if (!columnDone[k]) { for (i=lastColumn[k]; i<lastColumn[k+1]; i++) { model.setColumnLower(i,baseModel.getColumnLower(i)); model.setColumnUpper(i,baseModel.getColumnUpper(i)); model.setColumnName(i,baseModel.getColumnName(i)); model.setColumnObjective(i,baseModel.getColumnObjective(i)); model.setColumnIsInteger(i,baseModel.getColumnIsInteger(i)); } } } // Put back any elements for (i=0; i<numberElements; i++) { model(rowInTriple(dTriple[i]),dTriple[i].column,dTriple[i].value); } delete [] dTriple; timeIt += CoinCpuTime()-time1; model.setLogLevel(1); assert (!model.differentModel(baseModel,false)); }
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; }
// See if rounding will give solution // Sets value of solution // Assumes rhs for original matrix still okay // At present only works with integers // Fix values if asked for // Returns 1 if solution, 0 if not int AbcRounding::solution(double & solutionValue, double * betterSolution) { // 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(AbcModel::AbcIntegerTolerance); double primalTolerance; solver->getDblParam(OsiPrimalTolerance, primalTolerance); int numberRows = matrix_.getNumRows(); int numberIntegers = model_->numberIntegers(); const int * integerVariable = model_->integerVariable(); int i; double direction = solver->getObjSense(); double newSolutionValue = direction * solver->getObjValue(); int returnCode = 0; // 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) { // See if we can do better //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]; double value = newSolution[iColumn]; assert(fabs(floor(value + 0.5) - value) < integerTolerance); 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); returnCode=1; } else { // Can easily happen //printf("Debug AbcRounding giving bad solution\n"); } } } delete [] newSolution; delete [] rowActivity; return returnCode; }
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 (); }