/* 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; }
/* First tries setting a variable to better value. If feasible then tries setting others. If not feasible then tries swaps Returns 1 if solution, 0 if not */ int CbcHeuristicVND::solution(double & solutionValue, double * betterSolution) { numCouldRun_++; int returnCode = 0; const double * bestSolution = model_->bestSolution(); if (!bestSolution) return 0; // No solution found yet #ifdef HEURISTIC_INFORM printf("Entering heuristic %s - nRuns %d numCould %d when %d\n", heuristicName(),numRuns_,numCouldRun_,when_); #endif if (numberSolutions_ < model_->getSolutionCount()) { // new solution - add info numberSolutions_ = model_->getSolutionCount(); int numberIntegers = model_->numberIntegers(); const int * integerVariable = model_->integerVariable(); int i; for (i = 0; i < numberIntegers; i++) { int iColumn = integerVariable[i]; const OsiObject * object = model_->object(i); // get original bounds double originalLower; double originalUpper; getIntegerInformation( object, originalLower, originalUpper); double value = bestSolution[iColumn]; if (value < originalLower) { value = originalLower; } else if (value > originalUpper) { value = originalUpper; } } } int numberNodes = model_->getNodeCount(); if (howOften_ == 100) { if (numberNodes < lastNode_ + 12) return 0; // Do at 50 and 100 if ((numberNodes > 40 && numberNodes <= 50) || (numberNodes > 90 && numberNodes < 100)) numberNodes = howOften_; } if ((numberNodes % howOften_) == 0 && (model_->getCurrentPassNumber() <= 1 || model_->getCurrentPassNumber() == 999999)) { lastNode_ = model_->getNodeCount(); OsiSolverInterface * solver = model_->solver(); int numberIntegers = model_->numberIntegers(); const int * integerVariable = model_->integerVariable(); const double * currentSolution = solver->getColSolution(); OsiSolverInterface * newSolver = cloneBut(3); // was model_->continuousSolver()->clone(); //const double * colLower = newSolver->getColLower(); //const double * colUpper = newSolver->getColUpper(); double primalTolerance; solver->getDblParam(OsiPrimalTolerance, primalTolerance); // Sort on distance double * distance = new double [numberIntegers]; int * which = new int [numberIntegers]; int i; int nFix = 0; double tolerance = 10.0 * primalTolerance; for (i = 0; i < numberIntegers; i++) { int iColumn = integerVariable[i]; const OsiObject * object = model_->object(i); // get original bounds double originalLower; double originalUpper; getIntegerInformation( object, originalLower, originalUpper); double valueInt = bestSolution[iColumn]; if (valueInt < originalLower) { valueInt = originalLower; } else if (valueInt > originalUpper) { valueInt = originalUpper; } baseSolution_[iColumn] = currentSolution[iColumn]; distance[i] = fabs(currentSolution[iColumn] - valueInt); which[i] = i; if (fabs(currentSolution[iColumn] - valueInt) < tolerance) nFix++; } CoinSort_2(distance, distance + numberIntegers, which); nDifferent_ = numberIntegers - nFix; stepSize_ = nDifferent_ / 10; k_ = stepSize_; //nFix = numberIntegers-stepSize_; for (i = 0; i < nFix; i++) { int j = which[i]; int iColumn = integerVariable[j]; const OsiObject * object = model_->object(i); // get original bounds double originalLower; double originalUpper; getIntegerInformation( object, originalLower, originalUpper); double valueInt = bestSolution[iColumn]; if (valueInt < originalLower) { valueInt = originalLower; } else if (valueInt > originalUpper) { valueInt = originalUpper; } double nearest = floor(valueInt + 0.5); newSolver->setColLower(iColumn, nearest); newSolver->setColUpper(iColumn, nearest); } delete [] distance; delete [] which; if (nFix > numberIntegers / 5) { //printf("%d integers have samish value\n",nFix); returnCode = smallBranchAndBound(newSolver, numberNodes_, betterSolution, solutionValue, model_->getCutoff(), "CbcHeuristicVND"); if (returnCode < 0) returnCode = 0; // returned on size else numRuns_++; if ((returnCode&1) != 0) numberSuccesses_++; //printf("return code %d",returnCode); if ((returnCode&2) != 0) { // could add cut returnCode &= ~2; //printf("could add cut with %d elements (if all 0-1)\n",nFix); } else { //printf("\n"); } numberTries_++; if ((numberTries_ % 10) == 0 && numberSuccesses_*3 < numberTries_) howOften_ += static_cast<int> (howOften_ * decayFactor_); } delete newSolver; } return returnCode; }
/* 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; }