multiobj_c.c#

/* 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. */

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include "gurobi_c.h"

#define MAXSTR 128

int
main(void)
{
  GRBenv   *env   = NULL;
  GRBenv   *menv  = NULL;
  GRBmodel *model = NULL;
  int       error = 0;
  int      *cind  = NULL;
  double   *cval  = NULL;
  char      buffer[MAXSTR];
  int e, i, status, nSolutions;
  double objn;

  /* Sample data */
  const int groundSetSize = 20;
  const int nSubsets      = 4;
  const int Budget        = 12;
  double Set[][20] =
    { { 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[] = {3, 2, 2, 1};
  double SetObjWeight[]   = {1.0, 0.25, 1.25, 1.0};

  /* Create environment */
  error = GRBloadenv(&env, "multiobj_c.log");
  if (error) goto QUIT;

  /* Create initial model */
  error = GRBnewmodel(env, &model, "multiobj_c", groundSetSize, NULL,
                      NULL, NULL, NULL, NULL);
  if (error) goto QUIT;

  /* get model environment */
  menv = GRBgetenv(model);
  if (!menv) {
    fprintf(stderr, "Error: could not get model environment\n");
    goto QUIT;
  }

  /* Initialize decision variables for ground set:
   * x[e] == 1 if element e is chosen for the covering. */
  for (e = 0; e < groundSetSize; e++) {
    sprintf(buffer, "El%d", e);
    error = GRBsetcharattrelement(model, "VType", e, GRB_BINARY);
    if (error) goto QUIT;

    error = GRBsetstrattrelement(model, "VarName", e, buffer);
    if (error) goto QUIT;
  }

  /* Make space for constraint data */
  cind = malloc(sizeof(int) * groundSetSize);
  if (!cind) goto QUIT;
  cval = malloc(sizeof(double) * groundSetSize);
  if (!cval) goto QUIT;

  /* Constraint: limit total number of elements to be picked to be at most
   * Budget */
  for (e = 0; e < groundSetSize; e++) {
    cind[e] = e;
    cval[e] = 1.0;
  }
  sprintf (buffer, "Budget");
  error = GRBaddconstr(model, groundSetSize, cind, cval, GRB_LESS_EQUAL,
                       (double)Budget, buffer);
  if (error) goto QUIT;

  /* Set global sense for ALL objectives */
  error = GRBsetintattr(model, GRB_INT_ATTR_MODELSENSE, GRB_MAXIMIZE);
  if (error) goto QUIT;

  /* Limit how many solutions to collect */
  error = GRBsetintparam(menv, GRB_INT_PAR_POOLSOLUTIONS, 100);
  if (error) goto QUIT;

  /* Set and configure i-th objective */
  for (i = 0; i < nSubsets; i++) {
    sprintf(buffer, "Set%d", i+1);

    error = GRBsetobjectiven(model, i, SetObjPriority[i], SetObjWeight[i],
                             1.0 + i, 0.01, buffer, 0.0, groundSetSize,
                             cind, Set[i]);
    if (error) goto QUIT;
  }

  /* Save problem */
  error = GRBwrite(model, "multiobj_c.lp");
  if (error) goto QUIT;
  error = GRBwrite(model, "multiobj_c.mps");
  if (error) goto QUIT;

  /* Optimize */
  error = GRBoptimize(model);
  if (error) goto QUIT;

  /* Status checking */
  error = GRBgetintattr(model, "Status", &status);
  if (error) goto QUIT;

  if (status == GRB_INF_OR_UNBD ||
      status == GRB_INFEASIBLE  ||
      status == GRB_UNBOUNDED     ) {
    printf("The model cannot be solved "
           "because it is infeasible or unbounded\n");
    goto QUIT;
  }
  if (status != GRB_OPTIMAL) {
    printf("Optimization was stopped with status %i\n", status);
    goto QUIT;
  }

  /* Print best selected set */
  error = GRBgetdblattrarray(model, GRB_DBL_ATTR_X, 0, groundSetSize, cval);
  if (error) goto QUIT;

  printf("Selected elements in best solution:\n\t");
  for (e = 0; e < groundSetSize; e++) {
    if (cval[e] < .9) continue;
    printf("El%d ", e);
  }

  /* Print number of solutions stored */
  error = GRBgetintattr(model, GRB_INT_ATTR_SOLCOUNT, &nSolutions);
  if (error) goto QUIT;
  printf("\nNumber of solutions found: %d\n", nSolutions);

  /* Print objective values of solutions */

  if (nSolutions > 10) nSolutions = 10;
  printf("Objective values for first %d solutions:\n", nSolutions);
  for (i = 0; i < nSubsets; i++) {
    error = GRBsetintparam(menv, GRB_INT_PAR_OBJNUMBER, i);
    if (error) goto QUIT;

    printf("\tSet %d:", i);
    for (e = 0; e < nSolutions; e++) {
      error = GRBsetintparam(menv, GRB_INT_PAR_SOLUTIONNUMBER, e);
      if (error) goto QUIT;

      error = GRBgetdblattr(model, GRB_DBL_ATTR_OBJNVAL, &objn);
      if (error) goto QUIT;

      printf(" %6g", objn);
    }
    printf("\n");
  }

QUIT:

  if (cind != NULL)  free(cind);
  if (cval != NULL)  free(cval);
  if (model != NULL) GRBfreemodel(model);
  if (env != NULL)   GRBfreeenv(env);

  return error;
}