} // END CreateMasterILP public static void Main(string[] args) { try { string fileName = "../../../../examples/data/atsp.dat"; // Check the command line arguments if (args.Length != 1 && args.Length != 2) { Usage(); return; } if (!(args[0].Equals("0") || args[0].Equals("1"))) { Usage(); return; } bool sepFracSols = (args[0].ToCharArray()[0] == '0' ? false : true); if (sepFracSols) { System.Console.WriteLine("Benders' cuts separated to cut off: " + "Integer and fractional infeasible solutions."); } else { System.Console.WriteLine("Benders' cuts separated to cut off: " + "Only integer infeasible solutions."); } if (args.Length == 2) { fileName = args[1]; } // Read arc_costs from data file (17 city problem) Data data = new Data(fileName); // create master ILP int numNodes = data.numNodes; Cplex cplex = new Cplex(); IIntVar[][] x = new IIntVar[numNodes][]; CreateMasterILP(cplex, data, x); // Create workerLP for Benders' cuts separation WorkerLP workerLP = new WorkerLP(numNodes); // Set up the cut callback to be used for separating Benders' cuts cplex.SetParam(Cplex.Param.Preprocessing.Presolve, false); // Set the maximum number of threads to 1. // This instruction is redundant: If MIP control callbacks are registered, // then by default CPLEX uses 1 (one) thread only. // Note that the current example may not work properly if more than 1 threads // are used, because the callback functions modify shared global data. // We refer the user to the documentation to see how to deal with multi-thread // runs in presence of MIP control callbacks. cplex.SetParam(Cplex.Param.Threads, 1); // Turn on traditional search for use with control callbacks cplex.SetParam(Cplex.Param.MIP.Strategy.Search, Cplex.MIPSearch.Traditional); cplex.Use(new BendersLazyConsCallback(x, workerLP)); if (sepFracSols) { cplex.Use(new BendersUserCutCallback(x, workerLP)); } // Solve the model and write out the solution if (cplex.Solve()) { System.Console.WriteLine(); System.Console.WriteLine("Solution status: " + cplex.GetStatus()); System.Console.WriteLine("Objective value: " + cplex.ObjValue); if (cplex.GetStatus().Equals(Cplex.Status.Optimal)) { // Write out the optimal tour int i, j; double[][] sol = new double[numNodes][]; int[] succ = new int[numNodes]; for (j = 0; j < numNodes; ++j) { succ[j] = -1; } for (i = 0; i < numNodes; ++i) { sol[i] = cplex.GetValues(x[i]); for (j = 0; j < numNodes; ++j) { if (sol[i][j] > 1e-03) { succ[i] = j; } } } System.Console.WriteLine("Optimal tour:"); i = 0; while (succ[i] != 0) { System.Console.Write(i + ", "); i = succ[i]; } System.Console.WriteLine(i); } else { System.Console.WriteLine("Solution status is not Optimal"); } } else { System.Console.WriteLine("No solution available"); } workerLP.End(); cplex.End(); } catch (ILOG.Concert.Exception ex) { System.Console.WriteLine("Concert Error: " + ex); } catch (InputDataReader.InputDataReaderException ex) { System.Console.WriteLine("Data Error: " + ex); } catch (System.IO.IOException ex) { System.Console.WriteLine("IO Error: " + ex); } } // END Main
internal BendersUserCutCallback(IIntVar[][] x, WorkerLP workerLP) { this.x = x; this.workerLP = workerLP; numNodes = x.Length; }
public static void Main(string[] args) { try { string fileName = "../../../../examples/data/atsp.dat"; // Check the command line arguments if ( args.Length != 1 && args.Length != 2 ) { Usage(); return; } if ( ! (args[0].Equals("0") || args[0].Equals("1")) ) { Usage(); return; } bool sepFracSols = (args[0].ToCharArray()[0] == '0' ? false : true); if ( sepFracSols ) { System.Console.WriteLine("Benders' cuts separated to cut off: " + "Integer and fractional infeasible solutions."); } else { System.Console.WriteLine("Benders' cuts separated to cut off: " + "Only integer infeasible solutions."); } if ( args.Length == 2 ) fileName = args[1]; // Read arc_costs from data file (17 city problem) Data data = new Data(fileName); // create master ILP int numNodes = data.numNodes; Cplex cplex = new Cplex(); IIntVar[][] x = new IIntVar[numNodes][]; CreateMasterILP(cplex, data, x); // Create workerLP for Benders' cuts separation WorkerLP workerLP = new WorkerLP(numNodes); // Set up the cut callback to be used for separating Benders' cuts cplex.SetParam(Cplex.Param.Preprocessing.Presolve, false); // Set the maximum number of threads to 1. // This instruction is redundant: If MIP control callbacks are registered, // then by default CPLEX uses 1 (one) thread only. // Note that the current example may not work properly if more than 1 threads // are used, because the callback functions modify shared global data. // We refer the user to the documentation to see how to deal with multi-thread // runs in presence of MIP control callbacks. cplex.SetParam(Cplex.Param.Threads, 1); // Turn on traditional search for use with control callbacks cplex.SetParam(Cplex.Param.MIP.Strategy.Search, Cplex.MIPSearch.Traditional); cplex.Use(new BendersLazyConsCallback(x, workerLP)); if ( sepFracSols ) cplex.Use(new BendersUserCutCallback(x, workerLP)); // Solve the model and write out the solution if ( cplex.Solve() ) { System.Console.WriteLine(); System.Console.WriteLine("Solution status: " + cplex.GetStatus()); System.Console.WriteLine("Objective value: " + cplex.ObjValue); if ( cplex.GetStatus().Equals(Cplex.Status.Optimal) ) { // Write out the optimal tour int i, j; double[][] sol = new double[numNodes][]; int[] succ = new int[numNodes]; for (j = 0; j < numNodes; ++j) succ[j] = -1; for (i = 0; i < numNodes; ++i) { sol[i] = cplex.GetValues(x[i]); for (j = 0; j < numNodes; ++j) { if ( sol[i][j] > 1e-03 ) succ[i] = j; } } System.Console.WriteLine("Optimal tour:"); i = 0; while ( succ[i] != 0 ) { System.Console.Write(i + ", "); i = succ[i]; } System.Console.WriteLine(i); } else { System.Console.WriteLine("Solution status is not Optimal"); } } else { System.Console.WriteLine("No solution available"); } workerLP.End(); cplex.End(); } catch (ILOG.Concert.Exception ex) { System.Console.WriteLine("Concert Error: " + ex); } catch (InputDataReader.InputDataReaderException ex) { System.Console.WriteLine("Data Error: " + ex); } catch (System.IO.IOException ex) { System.Console.WriteLine("IO Error: " + ex); } }