static void Main() { try { // Sample data int groundSetSize = 20; int nSubsets = 4; int Budget = 12; double[,] Set = new double[, ] { { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1 }, { 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0 }, { 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0 } }; int[] SetObjPriority = new int[] { 3, 2, 2, 1 }; double[] SetObjWeight = new double[] { 1.0, 0.25, 1.25, 1.0 }; int e, i, status, nSolutions; // Create environment GRBEnv env = new GRBEnv("multiobj_cs.log"); // Create initial model GRBModel model = new GRBModel(env); model.ModelName = "multiobj_cs"; // Initialize decision variables for ground set: // x[e] == 1 if element e is chosen for the covering. GRBVar[] Elem = model.AddVars(groundSetSize, GRB.BINARY); for (e = 0; e < groundSetSize; e++) { string vname = string.Format("El{0}", e); Elem[e].VarName = vname; } // Constraint: limit total number of elements to be picked to be at most // Budget GRBLinExpr lhs = new GRBLinExpr(); for (e = 0; e < groundSetSize; e++) { lhs.AddTerm(1.0, Elem[e]); } model.AddConstr(lhs, GRB.LESS_EQUAL, Budget, "Budget"); // Set global sense for ALL objectives model.ModelSense = GRB.MAXIMIZE; // Limit how many solutions to collect model.Parameters.PoolSolutions = 100; // Set and configure i-th objective for (i = 0; i < nSubsets; i++) { string vname = string.Format("Set{0}", i); GRBLinExpr objn = new GRBLinExpr(); for (e = 0; e < groundSetSize; e++) { objn.AddTerm(Set[i, e], Elem[e]); } model.SetObjectiveN(objn, i, SetObjPriority[i], SetObjWeight[i], 1.0 + i, 0.01, vname); } // Save problem model.Write("multiobj_cs.lp"); // Optimize model.Optimize(); // Status checking status = model.Status; if (status == GRB.Status.INF_OR_UNBD || status == GRB.Status.INFEASIBLE || status == GRB.Status.UNBOUNDED) { Console.WriteLine("The model cannot be solved " + "because it is infeasible or unbounded"); return; } if (status != GRB.Status.OPTIMAL) { Console.WriteLine("Optimization was stopped with status {0}", status); return; } // Print best selected set Console.WriteLine("Selected elements in best solution:"); Console.Write("\t"); for (e = 0; e < groundSetSize; e++) { if (Elem[e].X < .9) { continue; } Console.Write("El{0} ", e); } Console.WriteLine(); // Print number of solutions stored nSolutions = model.SolCount; Console.WriteLine("Number of solutions found: {0}", nSolutions); // Print objective values of solutions if (nSolutions > 10) { nSolutions = 10; } Console.WriteLine("Objective values for first {0} solutions:", nSolutions); for (i = 0; i < nSubsets; i++) { model.Parameters.ObjNumber = i; Console.Write("\tSet" + i); for (e = 0; e < nSolutions; e++) { model.Parameters.SolutionNumber = e; Console.Write("{0,8}", model.ObjNVal); } Console.WriteLine(); } model.Dispose(); env.Dispose(); } catch (GRBException e) { Console.WriteLine("Error code = {0}", e); Console.WriteLine(e.Message); } }
static void Main() { try { // Sample data // Sets of days and workers string[] Shifts = new string[] { "Mon1", "Tue2", "Wed3", "Thu4", "Fri5", "Sat6", "Sun7", "Mon8", "Tue9", "Wed10", "Thu11", "Fri12", "Sat13", "Sun14" }; string[] Workers = new string[] { "Amy", "Bob", "Cathy", "Dan", "Ed", "Fred", "Gu", "Tobi" }; int nShifts = Shifts.Length; int nWorkers = Workers.Length; // Number of workers required for each shift double[] shiftRequirements = new double[] { 3, 2, 4, 4, 5, 6, 5, 2, 2, 3, 4, 6, 7, 5 }; // Worker availability: 0 if the worker is unavailable for a shift double[,] availability = new double[, ] { { 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1 }, { 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0 }, { 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1 }, { 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 }, { 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1 }, { 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1 }, { 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1 }, { 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } }; // Create environment GRBEnv env = new GRBEnv(); // Create initial model GRBModel model = new GRBModel(env); model.ModelName = "workforce5_cs"; // Initialize assignment decision variables: // x[w][s] == 1 if worker w is assigned to shift s. // This is no longer a pure assignment model, so we must // use binary variables. GRBVar[,] x = new GRBVar[nWorkers, nShifts]; for (int w = 0; w < nWorkers; ++w) { for (int s = 0; s < nShifts; ++s) { x[w, s] = model.AddVar(0, availability[w, s], 0, GRB.BINARY, string.Format("{0}.{1}", Workers[w], Shifts[s])); } } // Slack variables for each shift constraint so that the shifts can // be satisfied GRBVar[] slacks = new GRBVar[nShifts]; for (int s = 0; s < nShifts; ++s) { slacks[s] = model.AddVar(0, GRB.INFINITY, 0, GRB.CONTINUOUS, string.Format("{0}Slack", Shifts[s])); } // Variable to represent the total slack GRBVar totSlack = model.AddVar(0, GRB.INFINITY, 0, GRB.CONTINUOUS, "totSlack"); // Variables to count the total shifts worked by each worker GRBVar[] totShifts = new GRBVar[nWorkers]; for (int w = 0; w < nWorkers; ++w) { totShifts[w] = model.AddVar(0, GRB.INFINITY, 0, GRB.CONTINUOUS, string.Format("{0}TotShifts", Workers[w])); } GRBLinExpr lhs; // Constraint: assign exactly shiftRequirements[s] workers // to each shift s, plus the slack for (int s = 0; s < nShifts; ++s) { lhs = new GRBLinExpr(); lhs.AddTerm(1.0, slacks[s]); for (int w = 0; w < nWorkers; ++w) { lhs.AddTerm(1.0, x[w, s]); } model.AddConstr(lhs, GRB.EQUAL, shiftRequirements[s], Shifts[s]); } // Constraint: set totSlack equal to the total slack lhs = new GRBLinExpr(); lhs.AddTerm(-1.0, totSlack); for (int s = 0; s < nShifts; ++s) { lhs.AddTerm(1.0, slacks[s]); } model.AddConstr(lhs, GRB.EQUAL, 0, "totSlack"); // Constraint: compute the total number of shifts for each worker for (int w = 0; w < nWorkers; ++w) { lhs = new GRBLinExpr(); lhs.AddTerm(-1.0, totShifts[w]); for (int s = 0; s < nShifts; ++s) { lhs.AddTerm(1.0, x[w, s]); } model.AddConstr(lhs, GRB.EQUAL, 0, string.Format("totShifts{0}", Workers[w])); } // Constraint: set minShift/maxShift variable to less <=/>= to the // number of shifts among all workers GRBVar minShift = model.AddVar(0, GRB.INFINITY, 0, GRB.CONTINUOUS, "minShift"); GRBVar maxShift = model.AddVar(0, GRB.INFINITY, 0, GRB.CONTINUOUS, "maxShift"); model.AddGenConstrMin(minShift, totShifts, GRB.INFINITY, "minShift"); model.AddGenConstrMax(maxShift, totShifts, -GRB.INFINITY, "maxShift"); // Set global sense for ALL objectives model.ModelSense = GRB.MINIMIZE; // Set primary objective model.SetObjectiveN(totSlack, 0, 2, 1.0, 2.0, 0.1, "TotalSlack"); // Set secondary objective model.SetObjectiveN(maxShift - minShift, 1, 1, 1.0, 0, 0, "Fairness"); // Save problem model.Write("workforce5_cs.lp"); // Optimize int status = solveAndPrint(model, totSlack, nWorkers, Workers, totShifts); if (status != GRB.Status.OPTIMAL) { return; } // Dispose of model and environment model.Dispose(); env.Dispose(); } catch (GRBException e) { Console.WriteLine("Error code: {0}. {1}", e.ErrorCode, e.Message); } }