multiobj_cs.cs#

/* Copyright 2024, Gurobi Optimization, LLC */

/* Want to cover three different sets but subject to a common budget of
   elements allowed to be used. However, the sets have different priorities to
   be covered; and we tackle this by using multi-objective optimization. */

using System;
using Gurobi;

class multiobj_cs {
  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);
    }
  }
}