NAG Library Manual, Mark 30.3
Interfaces:  FL   CL   CPP   AD 

NAG CL Interface Introduction
Example description
/* nag_mip_handle_solve_minlp (h02ddc) Example Program.
 *
 * Copyright 2024 Numerical Algorithms Group.
 *
 * Mark 30.3, 2024.
 */

#include <math.h>
#include <nag.h>
#include <stdio.h>

#ifdef __cplusplus
extern "C" {
#endif
static void NAG_CALL objfun(Integer nvar, const double x[], double *fx,
                            Integer *flag, Nag_Comm *comm);
static void NAG_CALL objgrd(Integer nvar, const double x[], Integer nnzfd,
                            double fdx[], Integer *flag, Nag_Comm *comm);
static void NAG_CALL confun(Integer nvar, const double x[], Integer ncnln,
                            double gx[], Integer *flag, Nag_Comm *comm);
static void NAG_CALL congrd(Integer nvar, const double x[], Integer nnzgd,
                            double gdx[], Integer *flag, Nag_Comm *comm);
#ifdef __cplusplus
}
#endif

int main(void) {
#define BIGBND 1.0E20
  /* Scalars */
  Integer exit_status = 0;
  Integer p, i, idlc, nvar, nclin, ncnln, nnzfd, nnzgd, flag, lgourp = 4;
  double rho;

  /* Arrays */
  double rinfo[100], stats[100], *x = 0;
  double *fdx = 0, *gdx = 0;
  Integer idxfd[4] = {1, 2, 3, 4};
  double bl[8] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
  double bu[8] = {BIGBND, BIGBND, BIGBND, BIGBND, 1.0, 1.0, 1.0, 1.0};
  double linbl[5] = {1.0, 0.0, 0.0, 0.0, 0.0};
  double linbu[5] = {1.0, BIGBND, BIGBND, BIGBND, BIGBND};
  double nlnbl[2] = {0.0, 0.0};
  double nlnbu[2] = {0.0, BIGBND};
  Integer irowb[12] = {1, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5};
  Integer icolb[12] = {1, 2, 3, 4, 1, 5, 2, 6, 3, 7, 4, 8};
  double b[12] = {1.0, 1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0,};
  Integer irowgd[4] = {1, 1, 1, 1};
  Integer icolgd[4] = {1, 2, 3, 4};
  Integer group[4] = {5, 6, 7, 8};
  char ptype[] = "BINARY";
  Integer iuser[1];
  double ruser[1];
  void *handle = 0;

  /* Nag Types */
  NagError fail;
  Nag_FileID nout;
  Nag_Comm comm;

  /* Problem size */
  nvar = 8;
  /* Objective gradient nonzero elements quantity */
  nnzfd = 4;
  /* Constraint jacobian nonzero elements quantity */
  nnzgd = 4;

  printf("nag_mip_handle_solve_minlp (h02ddc) Example Program Results\n\n");
  fflush(stdout);

  /* nag_opt_handle_init (e04rac).
   * Initialize an empty problem handle with NVAR variables.
   */
  nag_opt_handle_init(&handle, nvar, NAGERR_DEFAULT);

  /* nag_opt_handle_set_simplebounds (e04rhc).
   * Define bounds on the variables
   */
  nag_opt_handle_set_simplebounds(handle, nvar, bl, bu, NAGERR_DEFAULT);

  /* nag_opt_handle_set_nlnobj (e04rgc).
   * Define nonlinear objective
   */
  nag_opt_handle_set_nlnobj(handle, nnzfd, idxfd, NAGERR_DEFAULT);

  /* Add one linear constraint */
  nclin = 5;
  idlc = 0;
  /* nag_opt_handle_set_linconstr (e04rjc).
   * Define a block of linear constraints
   */
  nag_opt_handle_set_linconstr(handle, nclin, linbl, linbu, 12, irowb,
                               icolb, b, &idlc, NAGERR_DEFAULT);

  /* Add two nonlinear constraints */
  ncnln = 2;

  /* nag_opt_handle_set_nlnconstr (e04rkc).
   * Define a block of nonlinear constraints
   */
  nag_opt_handle_set_nlnconstr(handle, ncnln, nlnbl, nlnbu, nnzgd, irowgd,
                               icolgd, NAGERR_DEFAULT);

  /* nag_opt_handle_set_property (e04rcc)
   * Define integer variables */
  nag_opt_handle_set_property(handle, ptype, lgourp, group, NAGERR_DEFAULT);

  if (!(x = NAG_ALLOC(nvar, double))) {
    printf("Allocation failure\n");
    exit_status = -1;
    goto END;
  }

  /* Initial estimate (binary variables need not be given) */
  x[0] = x[1] = x[2] = x[3] = 1.0;
  x[4] = x[5] = x[6] = x[7] = 0.0;

  /* Disable printing */
  nag_opt_handle_opt_set(handle, "Print Level = 0", NAGERR_DEFAULT);
  /* Do not print options */
  nag_opt_handle_opt_set(handle, "Print Options = No", NAGERR_DEFAULT);
  /* Do not print solution, x and f(x) will be printed afterwards */
  nag_opt_handle_opt_set(handle, "Print Solution = No", NAGERR_DEFAULT);

  /* Portfolio parameters */
  p = 3;
  rho = 10.0;
  iuser[0] = p;
  comm.iuser = iuser;
  ruser[0] = rho;
  comm.user = ruser;

  INIT_FAIL(fail);
  /* nag_mip_handle_solve_minlp (h02ddc).
   * Call the solver
   */
  nag_mip_handle_solve_minlp(handle, objfun, objgrd, confun, congrd, NULLFN, 
      nvar, x, rinfo, stats, &comm, &fail);

  if (fail.code == NE_NOERROR) {
    NAG_FREE(fdx);
    NAG_FREE(gdx);

    /* Results */
    printf("\nFinal estimate:");
    for (i = 0; i < nvar; i++) {
      printf("\nx[%4" NAG_IFMT "] = %12.4f", i + 1, x[i]);
    }
    printf("\n\nOptimised value = %12.4g\n", rinfo[0]);
  } else {
    printf("Error from nag_mip_handle_solve_minlp (h02ddc).\n%s\n",
           fail.message);
    exit_status = 1;
  }
  if (handle)
    /* nag_opt_handle_free (e04rzc).
     * Destroy the problem handle and deallocate all the memory used
     */
    nag_opt_handle_free(&handle, NAGERR_DEFAULT);

  NAG_FREE(x);

END:
  return exit_status;
}

/* Subroutine */
static void NAG_CALL objfun(Integer nvar, const double x[], double *fx,
                            Integer *flag, Nag_Comm *comm) {
  *flag = 0;
  *fx =  x[0] * (4.0 * x[0] + 3.0 * x[1] - x[2])
         + x[1] * (3.0 * x[0] + 6.0 * x[1] + x[2])
         + x[2] * (x[1] - x[0] + 10.0 * x[2]);

}
static void NAG_CALL objgrd(Integer nvar, const double x[], Integer nnzfd,
                            double fdx[], Integer *flag, Nag_Comm *comm) {
  *flag = 0;
  fdx[0] = 8.0 * x[0] + 6.0 * x[1] - 2.0 * x[2];
  fdx[1] = 6.0 * x[0] + 12.0 * x[1] + 2.0 * x[2];
  fdx[2] = 2.0 * (x[1] - x[0]) + 20.0 * x[2];
  fdx[3] = 0.0;

}
static void NAG_CALL confun(Integer nvar, const double x[], Integer ncnln,
                            double gx[], Integer *flag, Nag_Comm *comm) {
  *flag = 0;

  Integer p = comm->iuser[0];
  double rho = comm->user[0];

  /* Mean return rho */
  gx[0] = 8.0 * x[0] + 9.0 * x[1] + 12.0 * x[2] + 7.0 * x[3] - rho;
  /* Maximum of p assets in portfolio */
  gx[1] = (double)p - x[4] - x[5] - x[6] - x[7];
}
static void NAG_CALL congrd(Integer nvar, const double x[], Integer nnzgd,
                            double gdx[], Integer *flag, Nag_Comm *comm) {
  *flag = 0;
  gdx[0] = 8.0;
  gdx[1] = 9.0;
  gdx[2] = 12.0;
  gdx[3] = 7.0;
}