//############################################################################# void MibSHeuristic::lowerObjHeuristic() { /* optimize wrt to lower-level objective over current feasible lp feasible region */ MibSModel * model = MibSModel_; OsiSolverInterface * oSolver = model->getSolver(); //OsiSolverInterface * hSolver = new OsiCbcSolverInterface(); OsiSolverInterface* hSolver = new OsiSymSolverInterface(); double objSense(model->getLowerObjSense()); int lCols(model->getLowerDim()); int uCols(model->getUpperDim()); int * lColIndices = model->getLowerColInd(); int * uColIndices = model->getUpperColInd(); double * lObjCoeffs = model->getLowerObjCoeffs(); //int tCols(lCols + uCols); int tCols(oSolver->getNumCols()); //assert(tCols == oSolver->getNumCols()); hSolver->loadProblem(*oSolver->getMatrixByCol(), oSolver->getColLower(), oSolver->getColUpper(), oSolver->getObjCoefficients(), oSolver->getRowLower(), oSolver->getRowUpper()); int j(0); for(j = 0; j < tCols; j++){ if(oSolver->isInteger(j)) hSolver->setInteger(j); } double * nObjCoeffs = new double[tCols]; int i(0), index(0); CoinZeroN(nObjCoeffs, tCols); for(i = 0; i < lCols; i++){ index = lColIndices[i]; nObjCoeffs[index] = lObjCoeffs[i]; } //MibS objective sense is the opposite of OSI's! hSolver->setObjSense(objSense); hSolver->setObjective(nObjCoeffs); //double cutoff(model->getCutoff()); double cutoff(model->getKnowledgeBroker()->getIncumbentValue()); if(model->getNumSolutions()){ CoinPackedVector objCon; //double rhs(cutoff * objSense); //double smlTol(1.0); double rhs(cutoff); for(i = 0; i < tCols; i++){ objCon.insert(i, oSolver->getObjCoefficients()[i] * oSolver->getObjSense()); } hSolver->addRow(objCon, - hSolver->getInfinity(), rhs); } if(0) hSolver->writeLp("lobjheurstic"); if(0){ dynamic_cast<OsiCbcSolverInterface *> (hSolver)->getModelPtr()->messageHandler()->setLogLevel(0); } else{ dynamic_cast<OsiSymSolverInterface *> (hSolver)->setSymParam("prep_level", -1); dynamic_cast<OsiSymSolverInterface *> (hSolver)->setSymParam("verbosity", -2); dynamic_cast<OsiSymSolverInterface *> (hSolver)->setSymParam("max_active_nodes", 1); } hSolver->branchAndBound(); if(hSolver->isProvenOptimal()){ double upperObjVal(0.0); /*****************NEW ******************/ MibSSolution *mibSol = NULL; OsiSolverInterface * lSolver = model->bS_->setUpModel(hSolver, true); if(0){ lSolver->writeLp("tmp"); } if(0){ dynamic_cast<OsiCbcSolverInterface *> (lSolver)->getModelPtr()->messageHandler()->setLogLevel(0); } else{ dynamic_cast<OsiSymSolverInterface *> (lSolver)->setSymParam("prep_level", -1); dynamic_cast<OsiSymSolverInterface *> (lSolver)->setSymParam("verbosity", -2); dynamic_cast<OsiSymSolverInterface *> (lSolver)->setSymParam("max_active_nodes", 1); } lSolver->branchAndBound(); if (lSolver->isProvenOptimal()){ const double * sol = hSolver->getColSolution(); double objVal(lSolver->getObjValue() * objSense); double etol(etol_); double lowerObj = getLowerObj(sol, objSense); double * optUpperSolutionOrd = new double[uCols]; double * optLowerSolutionOrd = new double[lCols]; CoinZeroN(optUpperSolutionOrd, uCols); CoinZeroN(optLowerSolutionOrd, lCols); if(fabs(objVal - lowerObj) < etol){ /** Current solution is bilevel feasible **/ for(i = 0; i < tCols; i++) upperObjVal += hSolver->getColSolution()[i] * oSolver->getObjCoefficients()[i]; mibSol = new MibSSolution(hSolver->getNumCols(), hSolver->getColSolution(), upperObjVal, model); model->storeSolution(BlisSolutionTypeHeuristic, mibSol); mibSol = NULL; } else{ /* solution is not bilevel feasible, create one that is */ const double * uSol = hSolver->getColSolution(); const double * lSol = lSolver->getColSolution(); int numElements(hSolver->getNumCols()); int i(0), pos(0), index(0); double * lpSolution = new double[numElements]; double upperObj(0.0); //FIXME: problem is still here. indices may be wrong. //also is all this necessary, or can we just paste together uSol and lSol? //this may be an old comment for(i = 0; i < numElements; i++){ pos = model->bS_->binarySearch(0, lCols - 1, i, lColIndices); if(pos < 0){ pos = model->bS_->binarySearch(0, uCols - 1, i, uColIndices); if (pos >= 0){ optUpperSolutionOrd[pos] = uSol[i]; } } else{ optLowerSolutionOrd[pos] = lSol[pos]; } } for(i = 0; i < uCols; i++){ index = uColIndices[i]; lpSolution[index] = optUpperSolutionOrd[i]; upperObj += optUpperSolutionOrd[i] * oSolver->getObjCoefficients()[index]; } for(i = 0; i < lCols; i++){ index = lColIndices[i]; lpSolution[index] = optLowerSolutionOrd[i]; upperObj += optLowerSolutionOrd[i] * oSolver->getObjCoefficients()[index]; } if(model->checkUpperFeasibility(lpSolution)){ mibSol = new MibSSolution(hSolver->getNumCols(), lpSolution, upperObj * oSolver->getObjSense(), model); model->storeSolution(BlisSolutionTypeHeuristic, mibSol); mibSol = NULL; } delete [] lpSolution; } } delete lSolver; } delete hSolver; }
/* Comments needed Returns 1 if solution, 0 if not */ int CbcHeuristicPivotAndFix::solution(double & /*solutionValue*/, double * /*betterSolution*/) { numCouldRun_++; // Todo: Ask JJHF what this for. std::cout << "Entering Pivot-and-Fix Heuristic" << std::endl; #ifdef HEURISTIC_INFORM printf("Entering heuristic %s - nRuns %d numCould %d when %d\n", heuristicName(),numRuns_,numCouldRun_,when_); #endif #ifdef FORNOW std::cout << "Lucky you! You're in the Pivot-and-Fix Heuristic" << std::endl; // The struct should be moved to member data typedef struct { int numberSolutions; int maximumSolutions; int numberColumns; double ** solution; int * numberUnsatisfied; } clpSolution; double start = CoinCpuTime(); OsiClpSolverInterface * clpSolverOriginal = dynamic_cast<OsiClpSolverInterface *> (model_->solver()); assert (clpSolverOriginal); OsiClpSolverInterface *clpSolver(clpSolverOriginal); ClpSimplex * simplex = clpSolver->getModelPtr(); // Initialize the structure holding the solutions clpSolution solutions; // Set typeStruct field of ClpTrustedData struct to one. // This tells Clp it's "Mahdi!" 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(); simplex->primal(); // ------------------------------------------------- // Get the problem information // - get the number of cols and rows int numCols = clpSolver->getNumCols(); int numRows = clpSolver->getNumRows(); // - get the right hand side of the rows const double * rhs = clpSolver->getRightHandSide(); // - find the integer variables bool * varClassInt = new bool[numCols]; int numInt = 0; for (int i = 0; i < numCols; i++) { if (clpSolver->isContinuous(i)) varClassInt[i] = 0; else { varClassInt[i] = 1; numInt++; } } // -Get the rows sense const char * rowSense; rowSense = clpSolver->getRowSense(); // -Get the objective coefficients const double *objCoefficients = clpSolver->getObjCoefficients(); double *originalObjCoeff = new double [numCols]; for (int i = 0; i < numCols; i++) originalObjCoeff[i] = objCoefficients[i]; // -Get the matrix of the problem 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]; } } // The newObj is the randomly perturbed constraint used to find new // corner points double * newObj = new double [numCols]; // Set the random seed srand ( time(NULL) + 1); int randNum; // We're going to add a new row to the LP formulation // after finding each new solution. // Adding a new row requires the new elements and the new indices. // The elements are original objective function coefficients. // The indicies are the (dense) columns indices stored in addRowIndex. // The rhs is the value of the new solution stored in solutionValue. int * addRowIndex = new int[numCols]; for (int i = 0; i < numCols; i++) addRowIndex[i] = i; // The number of feasible solutions found by the PF heuristic. // This controls the return code of the solution() method. int numFeasibles = 0; // Shuffle the rows 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 + (rand() % (numRows - i)); index[i] = index[randNumTemp]; index[randNumTemp] = temp; } // In the clpSolution struct, we store a lot of column solutions. // For each perturb objective, we store the solution from each // iteration of the LP solve. // For each perturb objective, we look at the collection of // solutions to do something extremly intelligent :-) // We could (and should..and will :-) wipe out the block of // solutions when we're done with them. But for now, we just move on // and store the next block of solutions for the next (perturbed) // objective. // The variable startIndex tells us where the new block begins. int startIndex = 0; // At most "fixThreshold" number of integer variables can be unsatisfied // for calling smallBranchAndBound(). // The PF Heuristic only fixes fixThreshold number of variables to // their integer values. Not more. Not less. The reason is to give // the smallBB some opportunity to find better solutions. If we fix // everything it might be too many (leading the heuristic to come up // with infeasibility rather than a useful result). // (This is an important paramater. And it is dynamically set.) double fixThreshold; /* if(numInt > 400) fixThreshold = 17*sqrt(numInt); if(numInt<=400 && numInt>100) fixThreshold = 5*sqrt(numInt); if(numInt<=100) fixThreshold = 4*sqrt(numInt); */ // Initialize fixThreshold based on the number of integer // variables if (numInt <= 100) fixThreshold = .35 * numInt; if (numInt > 100 && numInt < 1000) fixThreshold = .85 * numInt; if (numInt >= 1000) fixThreshold = .1 * numInt; // Whenever the dynamic system for changing fixThreshold // kicks in, it changes the parameter by the // fixThresholdChange amount. // (The 25% should be member data and tuned. Another paper!) double fixThresholdChange = 0.25 * fixThreshold; // maxNode is the maximum number of nodes we allow smallBB to // search. It's initialized to 400 and changed dynamically. // The 400 should be member data, if we become virtuous. int maxNode = 400; // We control the decision to change maxNode through the boolean // variable changeMaxNode. The boolean variable is initialized to // true and gets set to false under a condition (and is never true // again.) // It's flipped off and stays off (in the current incarnation of PF) bool changeMaxNode = 1; // The sumReturnCode is used for the dynamic system that sets // fixThreshold and changeMaxNode. // // We track what's happening in sumReturnCode. There are 8 switches. // The first 5 switches corresponds to a return code for smallBB. // // We want to know how many times we consecutively get the same // return code. // // If "good" return codes are happening often enough, we're happy. // // If a "bad" returncodes happen consecutively, we want to // change something. // // The switch 5 is the number of times PF didn't call smallBB // becuase the number of integer variables that took integer values // was less than fixThreshold. // // The swicth 6 was added for a brilliant idea...to be announced // later (another paper!) // // The switch 7 is the one that changes the max node. Read the // code. (Todo: Verbalize the brilliant idea for the masses.) // int sumReturnCode[8]; /* sumReturnCode[0] ~ -1 --> problem too big for smallBB sumReturnCode[1] ~ 0 --> smallBB not finshed and no soln sumReturnCode[2] ~ 1 --> smallBB not finshed and there is a soln sumReturnCode[3] ~ 2 --> smallBB finished and no soln sumReturnCode[4] ~ 3 --> smallBB finished and there is a soln sumReturnCode[5] ~ didn't call smallBranchAndBound too few to fix sumReturnCode[6] ~ didn't call smallBranchAndBound too many unsatisfied sumReturnCode[7] ~ the same as sumReturnCode[1] but becomes zero just if the returnCode is not 0 */ for (int i = 0; i < 8; i++) sumReturnCode[i] = 0; int * colIndex = new int[numCols]; for (int i = 0; i < numCols; i++) colIndex[i] = i; double cutoff = COIN_DBL_MAX; bool didMiniBB; // Main loop for (int i = 0; i < numRows; i++) { // track the number of mini-bb for the dynamic threshold setting didMiniBB = 0; for (int k = startIndex; k < solutions.numberSolutions; k++) //if the point has 0 unsatisfied variables; make sure it is //feasible. Check integer feasiblity and constraints. if (solutions.numberUnsatisfied[k] == 0) { double feasibility = 1; //check integer feasibility for (int icol = 0; icol < numCols; icol++) { double closest = floor(solutions.solution[k][icol] + 0.5); if (varClassInt[icol] && (fabs(solutions.solution[k][icol] - closest) > 1e-6)) { feasibility = 0; break; } } //check if the solution satisfies the constraints for (int irow = 0; irow < numRows; irow++) { double lhs = 0; for (int j = 0; j < numCols; j++) lhs += matrix[irow][j] * solutions.solution[k][j]; if (rowSense[irow] == 'L' && lhs > rhs[irow] + 1e-6) { feasibility = 0; break; } if (rowSense[irow] == 'G' && lhs < rhs[irow] - 1e-6) { feasibility = 0; break; } if (rowSense[irow] == 'E' && (lhs - rhs[irow] > 1e-6 || lhs - rhs[irow] < -1e-6)) { feasibility = 0; break; } } //if feasible, find the objective value and set the cutoff // for the smallBB and add a new constraint to the LP // (and update the best solution found so far for the // return arguments) if (feasibility) { double objectiveValue = 0; for (int j = 0; j < numCols; j++) objectiveValue += solutions.solution[k][j] * originalObjCoeff[j]; cutoff = objectiveValue; clpSolver->addRow(numCols, addRowIndex, originalObjCoeff, -COIN_DBL_MAX, cutoff); // Todo: pick up the best solution in the block (not // the last). solutionValue = objectiveValue; for (int m = 0; m < numCols; m++) betterSolution[m] = solutions.solution[k][m]; numFeasibles++; } } // Go through the block of solution and decide if to call smallBB for (int k = startIndex; k < solutions.numberSolutions; k++) { if (solutions.numberUnsatisfied[k] <= fixThreshold) { // get new copy OsiSolverInterface * newSolver; newSolver = new OsiClpSolverInterface(*clpSolver); newSolver->setObjSense(1); newSolver->setObjective(originalObjCoeff); int numberColumns = newSolver->getNumCols(); int numFixed = 0; // Fix the first fixThreshold number of integer vars // that are satisfied for (int iColumn = 0 ; iColumn < numberColumns ; iColumn++) { if (newSolver->isInteger(iColumn)) { double value = solutions.solution[k][iColumn]; double intValue = floor(value + 0.5); if (fabs(value - intValue) < 1.0e-5) { newSolver->setColLower(iColumn, intValue); newSolver->setColUpper(iColumn, intValue); numFixed++; if (numFixed > numInt - fixThreshold) break; } } } COIN_DETAIL_PRINT(printf("numFixed: %d\n", numFixed)); COIN_DETAIL_PRINT(printf("fixThreshold: %f\n", fixThreshold)); COIN_DETAIL_PRINT(printf("numInt: %d\n", numInt)); double *newSolution = new double[numCols]; double newSolutionValue; // Call smallBB on the modified problem int returnCode = smallBranchAndBound(newSolver, maxNode, newSolution, newSolutionValue, cutoff, "mini"); // If smallBB found a solution, update the better // solution and solutionValue (we gave smallBB our // cutoff, so it only finds improving solutions) if (returnCode == 1 || returnCode == 3) { numFeasibles ++; solutionValue = newSolutionValue; for (int m = 0; m < numCols; m++) betterSolution[m] = newSolution[m]; COIN_DETAIL_PRINT(printf("cutoff: %f\n", newSolutionValue)); COIN_DETAIL_PRINT(printf("time: %.2lf\n", CoinCpuTime() - start)); } didMiniBB = 1; COIN_DETAIL_PRINT(printf("returnCode: %d\n", returnCode)); //Update sumReturnCode array for (int iRC = 0; iRC < 6; iRC++) { if (iRC == returnCode + 1) sumReturnCode[iRC]++; else sumReturnCode[iRC] = 0; } if (returnCode != 0) sumReturnCode[7] = 0; else sumReturnCode[7]++; if (returnCode == 1 || returnCode == 3) { cutoff = newSolutionValue; clpSolver->addRow(numCols, addRowIndex, originalObjCoeff, -COIN_DBL_MAX, cutoff); COIN_DETAIL_PRINT(printf("******************\n\n*****************\n")); } break; } } if (!didMiniBB && solutions.numberSolutions - startIndex > 0) { sumReturnCode[5]++; for (int iRC = 0; iRC < 5; iRC++) sumReturnCode[iRC] = 0; } //Change "fixThreshold" if needed // using the data we've recorded in sumReturnCode if (sumReturnCode[1] >= 3) fixThreshold -= fixThresholdChange; if (sumReturnCode[7] >= 3 && changeMaxNode) { maxNode *= 5; changeMaxNode = 0; } if (sumReturnCode[3] >= 3 && fixThreshold < 0.95 * numInt) fixThreshold += fixThresholdChange; if (sumReturnCode[5] >= 4) fixThreshold += fixThresholdChange; if (sumReturnCode[0] > 3) fixThreshold -= fixThresholdChange; startIndex = solutions.numberSolutions; //Check if the maximum iterations limit is reached // rlh: Ask John how this is working with the change to trustedUserPtr. if (solutions.numberSolutions > 20000) break; // The first time in this loop PF solves orig LP. //Generate the random objective function randNum = rand() % 10 + 1; randNum = fmod(randNum, 2); for (int j = 0; j < numCols; j++) { if (randNum == 1) if (fabs(matrix[index[i]][j]) < 1e-6) newObj[j] = 0.1; else newObj[j] = matrix[index[i]][j] * 1.1; else if (fabs(matrix[index[i]][j]) < 1e-6) newObj[j] = -0.1; else newObj[j] = matrix[index[i]][j] * 0.9; } clpSolver->setObjective(newObj); if (rowSense[i] == 'L') clpSolver->setObjSense(-1); else // Todo #1: We don't need to solve the LPs to optimality. // We just need corner points. // There's a problem in stopping Clp that needs to be looked // into. So for now, we solve optimality. clpSolver->setObjSense(1); // simplex->setMaximumIterations(100); clpSolver->getModelPtr()->primal(1); // simplex->setMaximumIterations(100000); #ifdef COIN_DETAIL printf("cutoff: %f\n", cutoff); printf("time: %.2f\n", CoinCpuTime() - start); for (int iRC = 0; iRC < 8; iRC++) printf("%d ", sumReturnCode[iRC]); printf("\nfixThreshold: %f\n", fixThreshold); printf("numInt: %d\n", numInt); printf("\n---------------------------------------------------------------- %d\n", i); #endif //temp: if (i > 3) break; } COIN_DETAIL_PRINT(printf("Best Feasible Found: %f\n", cutoff)); COIN_DETAIL_PRINT(printf("Total time: %.2f\n", CoinCpuTime() - start)); if (numFeasibles == 0) { return 0; } // We found something better std::cout << "See you soon! You're leaving the Pivot-and-Fix Heuristic" << std::endl; std::cout << std::endl; return 1; #endif return 0; }
//----------------------------------------------------------------------------- // Generate Lift-and-Project cuts //------------------------------------------------------------------- void CglLiftAndProject::generateCuts(const OsiSolverInterface& si, OsiCuts& cs, const CglTreeInfo /*info*/) { // Assumes the mixed 0-1 problem // // min {cx: <Atilde,x> >= btilde} // // is in canonical form with all bounds, // including x_t>=0, -x_t>=-1 for x_t binary, // explicitly stated in the constraint matrix. // See ~/COIN/Examples/Cgl2/cgl2.cpp // for a general purpose "convert" function. // Reference [BCC]: Balas, Ceria, and Corneujols, // "A lift-and-project cutting plane algorithm // for mixed 0-1 program", Math Prog 58, (1993) // 295-324. // This implementation uses Normalization 1. // Given canonical problem and // the lp-relaxation solution, x, // the LAP cut generator attempts to construct // a cut for every x_j such that 0<x_j<1 // [BCC:307] // x_j is the strictly fractional binary variable // the cut is generated from int j = 0; // Get basic problem information // let Atilde be an m by n matrix const int m = si.getNumRows(); const int n = si.getNumCols(); const double * x = si.getColSolution(); // Remember - Atildes may have gaps.. const CoinPackedMatrix * Atilde = si.getMatrixByRow(); const double * AtildeElements = Atilde->getElements(); const int * AtildeIndices = Atilde->getIndices(); const CoinBigIndex * AtildeStarts = Atilde->getVectorStarts(); const int * AtildeLengths = Atilde->getVectorLengths(); const int AtildeFullSize = AtildeStarts[m]; const double * btilde = si.getRowLower(); // Set up memory for system (10) [BCC:307] // (the problem over the norm intersected // with the polar cone) // // min <<x^T,Atilde^T>,u> + x_ju_0 // s.t. // <B,w> = (0,...,0,beta_,beta)^T // w is nonneg for all but the // last two entries, which are free. // where // w = (u,v,v_0,u_0)in BCC notation // u and v are m-vectors; u,v >=0 // v_0 and u_0 are free-scalars, and // // B = Atilde^T -Atilde^T -e_j e_j // btilde^T e_0^T 0 0 // e_0^T btilde^T 1 0 // ^T indicates Transpose // e_0 is a (AtildeNCols x 1) vector of all zeros // e_j is e_0 with a 1 in the jth position // Storing B in column order. B is a (n+2 x 2m+2) matrix // But need to allow for possible gaps in Atilde. // At each iteration, only need to change 2 cols and objfunc // Sane design of OsiSolverInterface does not permit mucking // with matrix. // Because we must delete and add cols to alter matrix, // and we can only add columns on the end of the matrix // put the v_0 and u_0 columns on the end. // rather than as described in [BCC] // Initially allocating B with space for v_0 and u_O cols // but not populating, for efficiency. // B without u_0 and v_0 is a (n+2 x 2m) size matrix. int twoM = 2*m; int BNumRows = n+2; int BNumCols = twoM+2; int BFullSize = 2*AtildeFullSize+twoM+3; double * BElements = new double[BFullSize]; int * BIndices = new int[BFullSize]; CoinBigIndex * BStarts = new CoinBigIndex [BNumCols+1]; int * BLengths = new int[BNumCols]; int i, ij, k=0; int nPlus1=n+1; int offset = AtildeStarts[m]+m; for (i=0; i<m; i++){ for (ij=AtildeStarts[i];ij<AtildeStarts[i]+AtildeLengths[i];ij++){ BElements[k]=AtildeElements[ij]; BElements[k+offset]=-AtildeElements[ij]; BIndices[k]= AtildeIndices[ij]; BIndices[k+offset]= AtildeIndices[ij]; k++; } BElements[k]=btilde[i]; BElements[k+offset]=btilde[i]; BIndices[k]=n; BIndices[k+offset]=nPlus1; BStarts[i]= AtildeStarts[i]+i; BStarts[i+m]=offset+BStarts[i];// = AtildeStarts[m]+m+AtildeStarts[i]+i BLengths[i]= AtildeLengths[i]+1; BLengths[i+m]= AtildeLengths[i]+1; k++; } BStarts[twoM]=BStarts[twoM-1]+BLengths[twoM-1]; // Cols that will be deleted each iteration int BNumColsLessOne=BNumCols-1; int BNumColsLessTwo=BNumCols-2; const int delCols[2] = {BNumColsLessOne, BNumColsLessTwo}; // Set lower bound on u and v // u_0, v_0 will be reset as free const double solverINFINITY = si.getInfinity(); double * BColLowers = new double[BNumCols]; double * BColUppers = new double[BNumCols]; CoinFillN(BColLowers,BNumCols,0.0); CoinFillN(BColUppers,BNumCols,solverINFINITY); // Set row lowers and uppers. // The rhs is zero, for but the last two rows. // For these the rhs is beta_ double * BRowLowers = new double[BNumRows]; double * BRowUppers = new double[BNumRows]; CoinFillN(BRowLowers,BNumRows,0.0); CoinFillN(BRowUppers,BNumRows,0.0); BRowLowers[BNumRows-2]=beta_; BRowUppers[BNumRows-2]=beta_; BRowLowers[BNumRows-1]=beta_; BRowUppers[BNumRows-1]=beta_; // Calculate base objective <<x^T,Atilde^T>,u> // Note: at each iteration coefficient u_0 // changes to <x^T,e_j> // w=(u,v,beta,v_0,u_0) size 2m+3 // So, BOjective[2m+2]=x[j] double * BObjective= new double[BNumCols]; double * Atildex = new double[m]; CoinFillN(BObjective,BNumCols,0.0); Atilde->times(x,Atildex); // Atildex is size m, x is size n CoinDisjointCopyN(Atildex,m,BObjective); // Number of cols and size of Elements vector // in B without the v_0 and u_0 cols int BFullSizeLessThree = BFullSize-3; // Load B matrix into a column orders CoinPackedMatrix CoinPackedMatrix * BMatrix = new CoinPackedMatrix(true, BNumRows, BNumColsLessTwo, BFullSizeLessThree, BElements,BIndices, BStarts,BLengths); // Assign problem into a solver interface // Note: coneSi will cleanup the memory itself OsiSolverInterface * coneSi = si.clone(false); coneSi->assignProblem (BMatrix, BColLowers, BColUppers, BObjective, BRowLowers, BRowUppers); // Problem sense should default to "min" by default, // but just to be virtuous... coneSi->setObjSense(1.0); // The plot outline from here on down: // coneSi has been assigned B without the u_0 and v_0 columns // Calculate base objective <<x^T,Atilde^T>,u> // bool haveWarmStart = false; // For (j=0; j<n, j++) // if (!isBinary(x_j) || x_j<=0 || x_j>=1) continue; // // IMPROVEME: if(haveWarmStart) check if j attractive // add {-e_j,0,-1} matrix column for v_0 // add {e_j,0,0} matrix column for u_0 // objective coefficient for u_0 is x_j // if (haveWarmStart) // set warmstart info // solve min{objw:Bw=0; w>=0,except v_0, u_0 free} // if (bounded) // get warmstart info // haveWarmStart=true; // ustar = optimal u solution // ustar_0 = optimal u_0 solution // alpha^T= <ustar^T,Atilde> -ustar_0e_j^T // (double check <alpha^T,x> >= beta_ should be violated) // add <alpha^T,x> >= beta_ to cutset // endif // delete column for u_0 // this deletes all column info. // delete column for v_0 // endFor // clean up memory // return 0; int * nVectorIndices = new int[n]; CoinIotaN(nVectorIndices, n, 0); bool haveWarmStart = false; bool equalObj1, equalObj2; CoinRelFltEq eq; double v_0Elements[2] = {-1,1}; double u_0Elements[1] = {1}; CoinWarmStart * warmStart = 0; double * ustar = new double[m]; CoinFillN(ustar, m, 0.0); double* alpha = new double[n]; CoinFillN(alpha, n, 0.0); for (j=0;j<n;j++){ if (!si.isBinary(j)) continue; // Better to ask coneSi? No! // coneSi has no binInfo. equalObj1=eq(x[j],0); equalObj2=eq(x[j],1); if (equalObj1 || equalObj2) continue; // IMPROVEME: if (haveWarmStart) check if j attractive; // AskLL:wanted to declare u_0 and v_0 packedVec outside loop // and setIndices, but didn't see a method to do that(?) // (Could "insert". Seems inefficient) int v_0Indices[2]={j,nPlus1}; int u_0Indices[1]={j}; // CoinPackedVector v_0(2,v_0Indices,v_0Elements,false); CoinPackedVector u_0(1,u_0Indices,u_0Elements,false); #if CGL_DEBUG const CoinPackedMatrix *see1 = coneSi->getMatrixByRow(); #endif coneSi->addCol(v_0,-solverINFINITY,solverINFINITY,0); coneSi->addCol(u_0,-solverINFINITY,solverINFINITY,x[j]); if(haveWarmStart) { coneSi->setWarmStart(warmStart); coneSi->resolve(); } else { #if CGL_DEBUG const CoinPackedMatrix *see2 = coneSi->getMatrixByRow(); #endif coneSi->initialSolve(); } if(coneSi->isProvenOptimal()){ warmStart = coneSi->getWarmStart(); haveWarmStart=true; const double * wstar = coneSi->getColSolution(); CoinDisjointCopyN(wstar, m, ustar); Atilde->transposeTimes(ustar,alpha); alpha[j]+=wstar[BNumCols-1]; #if debug int p; double sum; for(p=0;p<n;p++)sum+=alpha[p]*x[p]; if (sum<=beta_){ throw CoinError("Cut not violated", "cutGeneration", "CglLiftAndProject"); } #endif // add <alpha^T,x> >= beta_ to cutset OsiRowCut rc; rc.setRow(n,nVectorIndices,alpha); rc.setLb(beta_); rc.setUb(solverINFINITY); cs.insert(rc); } // delete col for u_o and v_0 coneSi->deleteCols(2,delCols); // clean up memory } // clean up delete [] alpha; delete [] ustar; delete [] nVectorIndices; // BMatrix, BColLowers,BColUppers, BObjective, BRowLowers, BRowUppers // are all freed by OsiSolverInterface destructor (?) delete [] BLengths; delete [] BStarts; delete [] BIndices; delete [] BElements; }
//############################################################################# OsiSolverInterface * MibSBilevel::setUpModel(OsiSolverInterface * oSolver, bool newOsi, const double *lpSol) { /** Create lower-level model with fixed upper-level vars **/ int probType = model_->MibSPar_->entry(MibSParams::bilevelProblemType); bool warmStartLL = model_->MibSPar_->entry(MibSParams::warmStartLL); bool doDualFixing = model_->MibSPar_->entry(MibSParams::doDualFixing); std::string feasCheckSolver = model_->MibSPar_->entry(MibSParams::feasCheckSolver); OsiSolverInterface * nSolver; double etol(model_->etol_); int i(0), j(0), index1(0), index2(0); int uCols(model_->getUpperDim()); int lRows(model_->getLowerRowNum()); int lCols(model_->getLowerDim()); int * uColIndices = model_->getUpperColInd(); int * lColIndices = model_->getLowerColInd(); int * lRowIndices = model_->getLowerRowInd(); double objSense(model_->getLowerObjSense()); double * lObjCoeffs = model_->getLowerObjCoeffs(); const CoinPackedMatrix * matrix = oSolver->getMatrixByRow(); double coeff(0.0); if (!lpSol){ lpSol = oSolver->getColSolution(); } const double * origRowLb = model_->getOrigRowLb(); const double * origRowUb = model_->getOrigRowUb(); const double * origColLb = model_->getOrigColLb(); const double * origColUb = model_->getOrigColUb(); double * rowUb = new double[lRows]; double * rowLb = new double[lRows]; double * colUb = new double[lCols]; double * colLb = new double[lCols]; //CoinZeroN(rowUb, lRows); //CoinZeroN(rowLb, lRows); //CoinZeroN(colUb, lCols); //CoinZeroN(colLb, lCols); /** Set the row bounds **/ for(i = 0; i < lRows; i++){ rowLb[i] = origRowLb[lRowIndices[i]]; rowUb[i] = origRowUb[lRowIndices[i]]; } for(i = 0; i < lCols; i++){ colLb[i] = origColLb[lColIndices[i]]; colUb[i] = origColUb[lColIndices[i]]; } if (newOsi){ if (feasCheckSolver == "Cbc"){ nSolver = new OsiCbcSolverInterface(); }else if (feasCheckSolver == "SYMPHONY"){ nSolver = new OsiSymSolverInterface(); }else if (feasCheckSolver == "CPLEX"){ #ifdef USE_CPLEX nSolver = new OsiCpxSolverInterface(); #else throw CoinError("CPLEX chosen as solver, but it has not been enabled", "setUpModel", "MibsBilevel"); #endif }else{ throw CoinError("Unknown solver chosen", "setUpModel", "MibsBilevel"); } int * integerVars = new int[lCols]; double * objCoeffs = new double[lCols]; CoinFillN(integerVars, lCols, 0); //CoinZeroN(objCoeffs, lCols); int intCnt(0); /** Fill in array of lower-level integer variables **/ for(i = 0; i < lCols; i++){ index1 = lColIndices[i]; if(oSolver->isInteger(index1)){ integerVars[intCnt] = i; intCnt++; } } CoinDisjointCopyN(lObjCoeffs, lCols, objCoeffs); CoinPackedMatrix * newMat = new CoinPackedMatrix(false, 0, 0); newMat->setDimensions(0, lCols); double tmp(0.0); /* for(i = 0; i < lRows; i++){ CoinPackedVector row; index1 = lRowIndices[i]; start = matStarts[index1]; end = start + matrix->getVectorSize(index1); for(j = start; j < end; j++){ index2 = matIndices[j]; //tmp = findIndex(index, lCols, lColIndices); tmp = binarySearch(0, lCols - 1, index2, lColIndices); if(tmp > -1) row.insert(tmp, matElements[j]); } newMat->appendRow(row); } */ for(i = 0; i < lRows; i++){ CoinPackedVector row; index1 = lRowIndices[i]; for(j = 0; j < lCols; j++){ index2 = lColIndices[j]; tmp = matrix->getCoefficient(index1, index2); row.insert(j, tmp); } newMat->appendRow(row); } /* nSolver->assignProblem(newMat, colLb, colUb, objCoeffs, rowLb, rowUb); */ nSolver->loadProblem(*newMat, colLb, colUb, objCoeffs, rowLb, rowUb); for(i = 0; i < intCnt; i++){ nSolver->setInteger(integerVars[i]); } //nSolver->setInteger(integerVars, intCnt); nSolver->setObjSense(objSense); //1 min; -1 max nSolver->setHintParam(OsiDoReducePrint, true, OsiHintDo); #if 0 if(0){ dynamic_cast<OsiCbcSolverInterface *> (nSolver)->getModelPtr()->messageHandler()->setLogLevel(0); } else{ dynamic_cast<OsiSymSolverInterface *> (nSolver)->setSymParam("prep_level", -1); dynamic_cast<OsiSymSolverInterface *> (nSolver)->setSymParam("verbosity", -2); dynamic_cast<OsiSymSolverInterface *> (nSolver)->setSymParam("max_active_nodes", 1); } #endif delete [] integerVars; }else{ nSolver = solver_; } #define SYM_VERSION_IS_WS strcmp(SYMPHONY_VERSION, "WS") #if SYMPHONY_VERSION_IS_WS if (feasCheckSolver == "SYMPHONY" && probType == 1 && warmStartLL && !newOsi && doDualFixing){ //Interdiction /** Get upper bound from best known (feasible) lower level solution and try to fix additional variables by sensitivity analysis **/ std::vector<std::pair<AlpsKnowledge*, double> > solutionPool; model_->getKnowledgeBroker()-> getAllKnowledges(AlpsKnowledgeTypeSolution, solutionPool); const double * sol; double objval, Ub(objSense*nSolver->getInfinity()); BlisSolution* blisSol; std::vector<std::pair<AlpsKnowledge*, double> >::const_iterator si; for (si = solutionPool.begin(); si != solutionPool.end(); ++si){ blisSol = dynamic_cast<BlisSolution*>(si->first); sol = blisSol->getValues(); for (i = 0; i < uCols; i++){ if (lpSol[uColIndices[i]] > 1 - etol && sol[lColIndices[i]] > 1-etol){ break; } } if (i == uCols && -objSense*blisSol->getQuality() < Ub){ Ub = -objSense*blisSol->getQuality(); } } /** Figure out which variables get fixed by the upper level solution **/ int *newUbInd = new int[uCols]; int *newLbInd = new int[uCols]; double *newUbVal = new double[uCols]; double *newLbVal = new double[uCols]; double newLb; for (i = 0; i < uCols; i++){ newUbInd[i] = uColIndices[i]; newLbInd[i] = uColIndices[i]; newLbVal[i] = 0; if (lpSol[uColIndices[i]] > 1 - etol){ newUbVal[i] = 0; }else{ newUbVal[i] = 1; } } /** If we found an upper bound, then do the dual fixing **/ if (Ub < objSense*nSolver->getInfinity()){ sym_environment *env = dynamic_cast<OsiSymSolverInterface *>(nSolver)->getSymphonyEnvironment(); for (i = 0; i < uCols; i++){ if (newUbVal[i] == 1){ // Try fixing it to zero newUbVal[i] = 0; sym_get_lb_for_new_rhs(env, 0, NULL, NULL, uCols, newLbInd, newLbVal, uCols, newUbInd, newUbVal, &newLb); if (objSense*newLb > Ub + etol){ //Victory! This variable can be fixed to 1 permanently newLbVal[i] = 1; } //Set upper bound back to 1 newUbVal[i] = 1; if (newLbVal[i] == 0){ // Try fixing it to one newLbVal[i] = 1; sym_get_lb_for_new_rhs(env, 0, NULL, NULL, uCols, newLbInd, newLbVal, uCols, newUbInd, newUbVal, &newLb); if (objSense*newLb > Ub + etol){ //Victory! This variable can be fixed to 0 permanently newUbVal[i] = 0; } newLbVal[i] = 0; } } } } /** Now set the row bounds to account for fixings **/ /** This is probably very frgaile. Assuming interdiction rows come last. It would be better to set variable bounds directly, but this doesn't seem to work right now. **/ int iRowStart = lRows-uCols; #if 1 for(i = iRowStart; i < lRows; i++){ nSolver->setRowLower(i, newLbVal[i-iRowStart]); nSolver->setRowUpper(i, newUbVal[i-iRowStart]); } #else for(i = 0; i < uCols; i++){ nSolver->setColLower(i, newLbVal[i]); nSolver->setColUpper(i, newUbVal[i]); } #endif delete[] newUbInd; delete[] newLbInd; delete[] newUbVal; delete[] newLbVal; }else{ #endif //FIXME: NEED TO GET ROW SENSE HERE /** Get contribution of upper-level columns **/ double * upComp = new double[lRows]; CoinFillN(upComp, lRows, 0.0); for(i = 0; i < lRows; i++){ index1 = lRowIndices[i]; for(j = 0; j < uCols; j++){ index2 = uColIndices[j]; coeff = matrix->getCoefficient(index1, index2); if (coeff != 0){ upComp[i] += coeff * lpSol[index2]; } } } /** Correct the row bounds to account for fixed upper-level vars **/ for(i = 0; i < lRows; i++){ nSolver->setRowLower(i, rowLb[i] - upComp[i]); nSolver->setRowUpper(i, rowUb[i] - upComp[i]); } delete [] upComp; #if SYMPHONY_VERSION_IS_WS } #endif //I don't think this is needed //if(!getWarmStart()) // setWarmStart(nSolver->getWarmStart()); return nSolver; }
int main(int argc, char **argv) { VRPH_version(); int i, j, k, n, status, num_attempts, *sol_buff, *IP_sol_buff; char in_file[200]; double lambda, best_heur_sol=VRP_INFINITY; bool first_sol=false, bootstrap=false;; VRPSolution *fresh_solution; OsiSolverInterface *si; const double *x; int last_num_cols=0, route_id=0; time_t start, stop; int *orderings[MAX_ROUTES]; for(i=0;i<MAX_ROUTES;i++) orderings[i]=NULL; // Set timing counters to 0 heur_time=mip_time=0; // Check arguments if(argc<5) { fprintf(stderr,"Usage: %s -f input_file -n num_runs [-v,-b,-c max_columns -d cols_to_delete]\n", argv[0]); fprintf(stderr,"\t Will solve the problem num_solutions times and add the routes\n"); fprintf(stderr,"\t to a set partitioning problem.\n"); fprintf(stderr,"\t Other options:\n"); fprintf(stderr,"\t -v runs in verbose mode\n"); fprintf(stderr,"\t -b will use bootstrapping where we send the set partitioning\n" "\t solution back to the metaheuristic solver\n"); fprintf(stderr,"\t -c max_columns will allow this many active columns/variables in the IP.\n"); fprintf(stderr,"\t Default value is max_columns=500\n"); fprintf(stderr,"\t -d num_cols_to_delete will delete this many columns once we have too many\n"); fprintf(stderr,"\t in the IP. Default value is num_cols_to_delete=100\n"); exit(-1); } // Set defaults verbose=false; max_columns=500; num_cols_to_delete=100; // Parse command line for(i=0;i<argc;i++) { if(strcmp(argv[i],"-f")==0) strcpy(in_file,argv[i+1]); if(strcmp(argv[i],"-n")==0) num_attempts=atoi(argv[i+1]); if(strcmp(argv[i],"-v")==0) verbose=true; if(strcmp(argv[i],"-b")==0) bootstrap=true; if(strcmp(argv[i],"-c")==0) max_columns=atoi(argv[i+1]); if(strcmp(argv[i],"-d")==0) num_cols_to_delete=atoi(argv[i+1]); } // This is the # of non-VRPH_DEPOT nodes n=VRPGetDimension(in_file); // This will be used to import/export solutions fresh_solution = new VRPSolution(n); // Create buffers for importing solutions sol_buff= new int[n+2]; IP_sol_buff = new int[n+2]; // Declare an OSI interface si=new OsiGlpkSolverInterface; si->setIntParam(OsiNameDiscipline,2); for(i=0;i<n;i++) { si->addRow(0,NULL,NULL,1,1); } // Declare a VRP of the right size and import the file VRP V(n); ClarkeWright CW(n); VRPRoute route(n); V.read_TSPLIB_file(in_file); // Set up a "route warehouse" to store the routes to be added to the IP V.route_wh=new VRPRouteWarehouse(HASH_TABLE_SIZE); // Set up a minimization problem si->setObjSense(1); // Set to error only output si->setHintParam(OsiDoReducePrint,true, OsiHintDo); // Unfortunately GLPK still prints out something regarding the conflict graph for(i=0;i<num_attempts;i++) { if(i==0 || !bootstrap) { lambda=.5+1.5*lcgrand(0); // Start with a clean VRP object V.reset(); CW.Construct(&V, lambda, false); if(verbose) printf("CW solution %d[%5.3f]: %f\n",i,lambda,V.get_total_route_length()-V.get_total_service_time()); } else // Use the solution from the IP V.import_solution_buff(IP_sol_buff); // Run VRPH's RTR algorithm to improve the solution start=clock(); V.RTR_solve(ONE_POINT_MOVE | TWO_POINT_MOVE | TWO_OPT | VRPH_USE_NEIGHBOR_LIST, 30, 5, 2, .01, 30, VRPH_LI_PERTURB, VRPH_FIRST_ACCEPT,false); stop=clock(); heur_time += (stop-start); if(verbose) printf("RTR Metaheuristic found solution %5.3f\n",V.get_total_route_length()-V.get_total_service_time()); // The RTR algorithm keeps a "warehouse" of the best solutions discovered during // the algorithm's search // Now go through the solutions in the solution warehouse and add the new routes // discovered to the IP for(j=0;j<V.solution_wh->num_sols;j++) { // Import solution j from the warehouse V.import_solution_buff(V.solution_wh->sols[j].sol); if(V.get_total_route_length()-V.get_total_service_time() < best_heur_sol) best_heur_sol = V.get_total_route_length()-V.get_total_service_time() ; // Now add the routes from this solution to the IP for(k=1;k<=V.get_total_number_of_routes();k++) { // Clean up the route by running INTRA_ROUTE optimizations only // using the route_search method of the different local search // heuristics, accepting improving moves only (VRPH_DOWNHILL) OnePointMove OPM; TwoOpt TO; ThreeOpt ThO; while(OPM.route_search(&V,k,k,VRPH_DOWNHILL|VRPH_INTRA_ROUTE_ONLY )){} while(TO.route_search(&V,k,k,VRPH_DOWNHILL|VRPH_INTRA_ROUTE_ONLY )){}; while(ThO.route_search(&V,k,VRPH_DOWNHILL|VRPH_INTRA_ROUTE_ONLY )){}; // Copy route k from the solution to the VRPRoute R V.update_route(k,&route); route.create_name(); // Add it to the "route warehouse" - this uses a hash table to keep track // of duplicate columns status=V.route_wh->add_route(&route); if(status!=DUPLICATE_ROUTE) { // This route is not currently in the WH and so it cannot be in the // set partitioning problem //OSI_add_route(si,&V,&route); OSI_add_route(si,&V,&route,route_id,orderings); route_id++; } } // Set the row RHS's if we need to if(first_sol) { first_sol=false; for(int rownum=0;rownum<n;rownum++) si->setRowBounds(rownum,1,1); // Note that changing this to >= would be a set covering problem // where each customer can be visited by more than one route } } // Now erase all the solutions from the WH V.solution_wh->liquidate(); if(verbose) { printf("Attempt %02d: Solving IP with %d columns\n",i,si->getNumCols()); printf("%d routes in the WH\n",V.route_wh->num_unique_routes); } // Solve the current set partitioning problem using the MIP solver start=clock(); si->branchAndBound(); stop=clock(); mip_time += (stop-start); double opt=si->getObjValue(); x=si->getColSolution(); last_num_cols=si->getNumCols(); if(verbose) printf("Optimal solution (%d columns) is %f\n",last_num_cols,opt); // Now recover the solution from the IP solution OSI_recover_solution(si, orderings, IP_sol_buff); if(verbose) printf("IP solution has obj. function value: %5.2f\n" "Best heuristic obj. function value: %5.2f\n", si->getObjValue(),best_heur_sol); } if(verbose) printf( "\nResults\n" "--------\n" "After %d runs\n" "IP solution has obj. function value: %5.2f\n" "Best heuristic obj. function value: %5.2f\n", num_attempts,si->getObjValue(),best_heur_sol); // print to stderr since GLPK prints "conflict graph" to stdout (a known bug...) // best_heur_sol best_mip_sol heur_time mip_time fprintf(stderr,"%5.3f %5.3f %5.3f %5.3f\n", best_heur_sol, si->getObjValue(), (double)(heur_time)/CLOCKS_PER_SEC, (double)(mip_time)/CLOCKS_PER_SEC); delete V.route_wh; delete fresh_solution; delete [] sol_buff; delete [] IP_sol_buff; delete si; for(i=0;i<MAX_ROUTES;i++) if(orderings[i]) delete [] orderings[i]; return 0; }
int CbcHeuristicNaive::solution(double & solutionValue, double * betterSolution) { numCouldRun_++; // See if to do bool atRoot = model_->getNodeCount() == 0; int passNumber = model_->getCurrentPassNumber(); if (!when() || (when() == 1 && model_->phase() != 1) || !atRoot || passNumber != 1) return 0; // switched off // Don't do if it was this heuristic which found solution! if (this == model_->lastHeuristic()) return 0; numRuns_++; double cutoff; model_->solver()->getDblParam(OsiDualObjectiveLimit, cutoff); double direction = model_->solver()->getObjSense(); cutoff *= direction; cutoff = CoinMin(cutoff, solutionValue); OsiSolverInterface * solver = model_->continuousSolver(); if (!solver) solver = model_->solver(); const double * colLower = solver->getColLower(); const double * colUpper = solver->getColUpper(); const double * objective = solver->getObjCoefficients(); int numberColumns = model_->getNumCols(); int numberIntegers = model_->numberIntegers(); const int * integerVariable = model_->integerVariable(); int i; bool solutionFound = false; CoinWarmStartBasis saveBasis; CoinWarmStartBasis * basis = dynamic_cast<CoinWarmStartBasis *>(solver->getWarmStart()) ; if (basis) { saveBasis = * basis; delete basis; } // First just fix all integers as close to zero as possible OsiSolverInterface * newSolver = cloneBut(7); // wassolver->clone(); for (i = 0; i < numberIntegers; i++) { int iColumn = integerVariable[i]; double lower = colLower[iColumn]; double upper = colUpper[iColumn]; double value; if (lower > 0.0) value = lower; else if (upper < 0.0) value = upper; else value = 0.0; newSolver->setColLower(iColumn, value); newSolver->setColUpper(iColumn, value); } newSolver->initialSolve(); if (newSolver->isProvenOptimal()) { double solValue = newSolver->getObjValue() * direction ; if (solValue < cutoff) { // we have a solution solutionFound = true; solutionValue = solValue; memcpy(betterSolution, newSolver->getColSolution(), numberColumns*sizeof(double)); COIN_DETAIL_PRINT(printf("Naive fixing close to zero gave solution of %g\n", solutionValue)); cutoff = solValue - model_->getCutoffIncrement(); } } // Now fix all integers as close to zero if zero or large cost int nFix = 0; for (i = 0; i < numberIntegers; i++) { int iColumn = integerVariable[i]; double lower = colLower[iColumn]; double upper = colUpper[iColumn]; double value; if (fabs(objective[i]) > 0.0 && fabs(objective[i]) < large_) { nFix++; if (lower > 0.0) value = lower; else if (upper < 0.0) value = upper; else value = 0.0; newSolver->setColLower(iColumn, value); newSolver->setColUpper(iColumn, value); } else { // set back to original newSolver->setColLower(iColumn, lower); newSolver->setColUpper(iColumn, upper); } } const double * solution = solver->getColSolution(); if (nFix) { newSolver->setWarmStart(&saveBasis); newSolver->setColSolution(solution); newSolver->initialSolve(); if (newSolver->isProvenOptimal()) { double solValue = newSolver->getObjValue() * direction ; if (solValue < cutoff) { // try branch and bound double * newSolution = new double [numberColumns]; COIN_DETAIL_PRINT(printf("%d fixed after fixing costs\n", nFix)); int returnCode = smallBranchAndBound(newSolver, numberNodes_, newSolution, solutionValue, solutionValue, "CbcHeuristicNaive1"); if (returnCode < 0) returnCode = 0; // returned on size if ((returnCode&2) != 0) { // could add cut returnCode &= ~2; } if (returnCode == 1) { // solution solutionFound = true; memcpy(betterSolution, newSolution, numberColumns*sizeof(double)); COIN_DETAIL_PRINT(printf("Naive fixing zeros gave solution of %g\n", solutionValue)); cutoff = solutionValue - model_->getCutoffIncrement(); } delete [] newSolution; } } } #if 1 newSolver->setObjSense(-direction); // maximize newSolver->setWarmStart(&saveBasis); newSolver->setColSolution(solution); for (int iColumn = 0; iColumn < numberColumns; iColumn++) { double value = solution[iColumn]; double lower = colLower[iColumn]; double upper = colUpper[iColumn]; double newLower; double newUpper; if (newSolver->isInteger(iColumn)) { newLower = CoinMax(lower, floor(value) - 2.0); newUpper = CoinMin(upper, ceil(value) + 2.0); } else { newLower = CoinMax(lower, value - 1.0e5); newUpper = CoinMin(upper, value + 1.0e-5); } newSolver->setColLower(iColumn, newLower); newSolver->setColUpper(iColumn, newUpper); } newSolver->initialSolve(); if (newSolver->isProvenOptimal()) { double solValue = newSolver->getObjValue() * direction ; if (solValue < cutoff) { nFix = 0; newSolver->setObjSense(direction); // correct direction //const double * thisSolution = newSolver->getColSolution(); for (int iColumn = 0; iColumn < numberColumns; iColumn++) { double value = solution[iColumn]; double lower = colLower[iColumn]; double upper = colUpper[iColumn]; double newLower = lower; double newUpper = upper; if (newSolver->isInteger(iColumn)) { if (value < lower + 1.0e-6) { nFix++; newUpper = lower; } else if (value > upper - 1.0e-6) { nFix++; newLower = upper; } else { newLower = CoinMax(lower, floor(value) - 2.0); newUpper = CoinMin(upper, ceil(value) + 2.0); } } newSolver->setColLower(iColumn, newLower); newSolver->setColUpper(iColumn, newUpper); } // try branch and bound double * newSolution = new double [numberColumns]; COIN_DETAIL_PRINT(printf("%d fixed after maximizing\n", nFix)); int returnCode = smallBranchAndBound(newSolver, numberNodes_, newSolution, solutionValue, solutionValue, "CbcHeuristicNaive1"); if (returnCode < 0) returnCode = 0; // returned on size if ((returnCode&2) != 0) { // could add cut returnCode &= ~2; } if (returnCode == 1) { // solution solutionFound = true; memcpy(betterSolution, newSolution, numberColumns*sizeof(double)); COIN_DETAIL_PRINT(printf("Naive maximizing gave solution of %g\n", solutionValue)); cutoff = solutionValue - model_->getCutoffIncrement(); } delete [] newSolution; } } #endif delete newSolver; return solutionFound ? 1 : 0; }