feasopt_c.c#

/* Copyright 2024, Gurobi Optimization, LLC */

/* This example reads a MIP model from a file, adds artificial
   variables to each constraint, and then minimizes the sum of the
   artificial variables.  A solution with objective zero corresponds
   to a feasible solution to the input model.
   We can also use FeasRelax feature to do it. In this example, we
   use minrelax=1, i.e. optimizing the returned model finds a solution
   that minimizes the original objective, but only from among those
   solutions that minimize the sum of the artificial variables. */

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

int
main(int   argc,
     char *argv[])
{
  GRBenv   *env       = NULL;
  GRBmodel *model     = NULL;
  GRBmodel *feasmodel = NULL;
  double   *rhspen      = NULL;
  int       error = 0;
  int       i, j;
  int       numvars, numconstrs;
  char      sense;
  int       vind[1];
  double    vval[1];
  double    feasobj;
  char      *cname, *vname;

  if (argc < 2)
  {
    fprintf(stderr, "Usage: feasopt_c filename\n");
    exit(1);
  }

  error = GRBloadenv(&env, "feasopt.log");
  if (error) goto QUIT;

  error = GRBreadmodel(env, argv[1], &model);
  if (error) goto QUIT;

  /* Create a copy to use FeasRelax feature later */

  feasmodel = GRBcopymodel(model);
  if (error) goto QUIT;

  /* clear objective */
  error = GRBgetintattr(model, "NumVars", &numvars);
  if (error) goto QUIT;
  for (j = 0; j < numvars; ++j)
  {
    error = GRBsetdblattrelement(model, "Obj", j, 0.0);
    if (error) goto QUIT;
  }

  /* add slack variables */
  error = GRBgetintattr(model, "NumConstrs", &numconstrs);
  if (error) goto QUIT;
  for (i = 0; i < numconstrs; ++i)
  {
    error = GRBgetcharattrelement(model, "Sense", i, &sense);
    if (error) goto QUIT;
    if (sense != '>')
    {
      error = GRBgetstrattrelement(model, "ConstrName", i, &cname);
      if (error) goto QUIT;
      vname = malloc(sizeof(char) * (6 + strlen(cname)));
      if (!vname) goto QUIT;
      strcpy(vname, "ArtN_");
      strcat(vname, cname);
      vind[0] = i;
      vval[0] = -1.0;
      error = GRBaddvar(model, 1, vind, vval, 1.0, 0.0, GRB_INFINITY,
                        GRB_CONTINUOUS, vname);
      if (error) goto QUIT;
      free(vname);
    }
    if (sense != '<')
    {
      error = GRBgetstrattrelement(model, "ConstrName", i, &cname);
      if (error) goto QUIT;
      vname = malloc(sizeof(char) * (6 + strlen(cname)));
      if (!vname) goto QUIT;
      strcpy(vname, "ArtP_");
      strcat(vname, cname);
      vind[0] = i;
      vval[0] = 1.0;
      error = GRBaddvar(model, 1, vind, vval, 1.0, 0.0, GRB_INFINITY,
                        GRB_CONTINUOUS, vname);
      if (error) goto QUIT;
      free(vname);
    }
  }

  /* Optimize modified model */

  error = GRBoptimize(model);
  if (error) goto QUIT;

  error = GRBwrite(model, "feasopt.lp");
  if (error) goto QUIT;

  /* Use FeasRelax feature */

  rhspen = (double *) malloc(numconstrs*sizeof(double));
  if (rhspen == NULL) {
    printf("ERROR: out of memory\n");
    goto QUIT;
  }

  /* set penalties for artificial variables */
  for (i = 0; i < numconstrs; i++) rhspen[i] = 1;

  /* create a FeasRelax model with the original objective recovered
     and enforcement on minimum of aretificial variables */
  error = GRBfeasrelax(feasmodel, GRB_FEASRELAX_LINEAR, 1,
                       NULL, NULL, rhspen, &feasobj);
  if (error) goto QUIT;

  /* optimize FeasRelax model */
  error = GRBwrite(feasmodel, "feasopt1.lp");
  if (error) goto QUIT;

  error = GRBoptimize(feasmodel);
  if (error) goto QUIT;


QUIT:

  /* Error reporting */

  if (error)
  {
    printf("ERROR: %s\n", GRBgeterrormsg(env));
    exit(1);
  }

  /* Free models, env and etc. */

  if (rhspen) free(rhspen);

  GRBfreemodel(model);
  GRBfreemodel(feasmodel);

  GRBfreeenv(env);

  return 0;
}