/*********************************************************************** Xpress Optimizer Examples ========================= file RoundInt.java ``````````````` Apply an integer fixing heuristic to a MIP problem. The program also demonstrates the use of the integer solution callback. (c) 2021-2023 Fair Isaac Corporation ***********************************************************************/ import com.dashoptimization.DefaultMessageListener; import com.dashoptimization.XPRS; import com.dashoptimization.XPRSintSolListener; import com.dashoptimization.XPRSprob; import static com.dashoptimization.XPRSenumerations.CutStrategy; /** Apply an integer fixing heuristic to a MIP problem. * * The program also demonstrates the use of the integer solution callback. * * We take the power generation problem stored in hpw15.mps which * seeks to optimise the operating pattern of a group of electricity * generators. We solve this MIP with a very loose integer tolerance * and then fix all binary and integer variables to their rounded * integer values, changing both their lower and upper bounds. We then * solve the resulting LP. * * The results are displayed on screen and the problem statistics * stored in a logfile. */ public class RoundInt { /** The very loose integrality tolerance we use in the example. */ public static final double TOL = 0,3; /** Run the example. * @param args The problem name. This is optional. If no problem name * is specified then "hpw15" is used. */ public static void main(String[] args) { String problem = args.length == 0 ? "../data/hpw15" : args[0]; if (args.length > 0) problem = args[0]; String logFile = "RountInt.log"; try (XPRSprob prob = new XPRSprob(null)) { // Delete and define log file new java.io.File(logFile).delete(); prob.setLogFile(logFile); // Install default output: We only print warning and error messages. prob.addMessageListener(new DefaultMessageListener(null, System.err, System.err)); // Read the problem file prob.readProb(problem); // Disable cuts - or the optimal solution will be found at the top // node and the integer solution callback will hardly be used. prob.controls().setCutStrategy(CutStrategy.NONE); // Solve MIP with loose integer tolerance // Set integer feasibility tolerance prob.controls().setMIPTol(TOL); // Tell Optimizer to print out MIP information at each node and // call IntSol whenever an integer solution is found prob.controls().setMIPLog(3); prob.addIntSolListener(new IntSol()); // Get the number of columns int cols = prob.attributes().getCols(); // Solve the MIP problem and get the solution values System.out.printf("Applying an integer fixing heuristic to problem %s:-%n%n", problem); System.out.printf("Solving MIP:%n%n"); prob.mipOptimize(); double[] x = prob.getMipSolX(); // Round off the values of all binary and integer variables XPRSprob.MIPEntityInfo info = prob.getDiscreteCols(); int mipents = info.coltype.length; int[] glInd = info.colind; byte[] glType = info.coltype; // Allocate memory for bound arrays int[] bndInd = new int[mipents]; double[] bndVal = new double[mipents]; byte[] bndType = new byte[mipents]; // Initialise bound counter int nBnd = 0; // Go through MIP entities for (int k = 0; k < mipents; ++k) { // Test whether each is a binary or integer variable if (glType[k] == 'B' || glType[k] == 'I') { // Hold the index of the variable int j = glInd[k]; // Store the index, round the variable's value to the // nearest integer, and reset both its upper and lower // bounds bndInd[nBnd] = j; bndVal[nBnd] = Math.round(x[j]); bndType[nBnd] = 'B'; ++nBnd; } } // Instruct Optimizer to change the bounds prob.chgBounds(nBnd, bndInd, bndType, bndVal); System.out.printf("\nAfter MIP search, %d binary and integer variables were fixed%n%n", nBnd); // Solve the resulting LP // Solve the LP and get the solution values prob.lpOptimize(); double[] y = prob.getLpSolX(); // Get and print the LP objective function value System.out.printf("After solving the LP the final objective value was %g%n%n", prob.attributes().getLPObjVal()); // Print the non-zero MIP and corresponding LP solution values for // comparison: System.out.printf("The non-zero MIP and LP solution values are:%n%n"); for (int j = 0; j < cols; ++j) { if (x[j] != 0.0) { System.out.printf(" x[%2d] = %5,1f %5,3g%n", j, x[j], y[j]); } } System.out.println(); } } /** Callback to display objective value associated with a node. */ private static final class IntSol implements XPRSintSolListener { /** Displays the objective value associated with a node in the MIP * search. * This function is called every time an integer solution has been * found. * @param prob The problem for which a solution was found. * @param vContext unused. */ @Override public void XPRSintSolEvent(XPRSprob prob, Object vContext) { // Get the node number int node = prob.attributes().getCurrentNode(); // Get the objective function value double obj = prob.attributes().getLPObjVal(); System.out.printf(" Node %d (Objective value = %g)%n", node, obj); } } }