/* nag_opt_sparse_mps_read (e04mzc) Example Program.
 *
 * Copyright 2017 Numerical Algorithms Group.
 *
 * Mark 26.1, 2017.
 *
 */

#include <nag.h>
#include <stdio.h>
#include <string.h>
#include <nag_stdlib.h>
#include <nag_string.h>
#include <nage04.h>

#ifdef __cplusplus
extern "C"
{
#endif
  static void NAG_CALL qphess(Integer ncolh, const double x[], double hx[],
                              Nag_Comm *comm);
#ifdef __cplusplus
}
#endif

int main(void)
{
  static double ruser[1] = { -1.0 };
  Integer exit_status = 0;
  Integer *ha, i, iobj, *ka, m, n, ncolh, ninf, nnz;
  Nag_E04_Opt options;
  double *a, *bl, *bu, obj, sinf, *xs;
  Nag_Comm comm;
  NagError fail;

  INIT_FAIL(fail);

  printf("nag_opt_sparse_mps_read (e04mzc) Example Program Results\n");

  /* For communication with user-supplied functions: */
  comm.user = ruser;

  fflush(stdout);
  /* Initialize the options structure and read MPSX data */
  /* nag_opt_init (e04xxc).
   * Initialization function for option setting
   */
  nag_opt_init(&options);
  strcpy(options.prob_name, "..QP 2..");
  strcpy(options.obj_name, "..COST..");

  printf("\n");
  printf("Reading MPSX file:\n");

  /* Turn off printing of intermediate output from
     nag_opt_sparse_mps_read() and nag_opt_sparse_convex_qp() */
  options.list = Nag_FALSE;
  options.output_level = Nag_NoOutput;
  options.print_level = Nag_NoPrint;

  /* nag_opt_sparse_mps_read (e04mzc), see above. */
  nag_opt_sparse_mps_read((char *) 0, &n, &m, &nnz, &iobj, &a, &ha, &ka, &bl,
                          &bu, &xs, &options, &fail);
  if (fail.code != NE_NOERROR) {
    printf("Error from nag_opt_sparse_mps_read (e04mzc).\n%s\n",
           fail.message);
    exit_status = 1;
    goto END;
  }
  printf("MPSX file contains %" NAG_IFMT " variables and %"
         NAG_IFMT " linear constraints\n", n, m);

  printf("\n");
  printf("Solving QP problem:\n");
  /* Column and row names are now available via options */
  ncolh = 5;
  /* nag_opt_sparse_convex_qp (e04nkc), see above. */
  nag_opt_sparse_convex_qp(n, m, nnz, iobj, ncolh, qphess, a, ha, ka, bl, bu,
                           xs, &ninf, &sinf, &obj, &options, &comm, &fail);
  if (fail.code != NE_NOERROR) {
    printf("Error from nag_opt_sparse_convex_qp (e04nkc).\n%s\n",
           fail.message);
    exit_status = 1;
  }

  if (fail.code != NE_NOERROR)
    {
      printf("Error from nag_opt_free (e04xzc).\n%s\n", fail.message);
      exit_status = 1;
      goto END;
    }
  else
    {
      printf("Optimal objective value: %11.3e\n", obj);
      printf("Optimal X:\n");
      for (i = 0; i < n; i++)
        printf("  x[%" NAG_IFMT "] = %8.4f\n", i, xs[i]);
    }

  /* Free memory returned by nag_opt_sparse_mps_read (e04mzc) */
  /* nag_opt_sparse_mps_free (e04myc), see above. */
  nag_opt_sparse_mps_free(&a, &ha, &ka, &bl, &bu, &xs);

  /* Free memory in options (including column & row names) */
  /* nag_opt_free (e04xzc).
   * Memory freeing function for use with option setting
   */
  nag_opt_free(&options, "all", &fail);

END:

  return exit_status;
}

static void NAG_CALL qphess(Integer ncolh, const double x[], double hx[],
                            Nag_Comm *comm)
{
  /* Function to compute H*x. */
  if (comm->user[0] == -1.0) {
    printf("(User-supplied callback qphess, first invocation.)\n");
    fflush(stdout);
    comm->user[0] = 0.0;
  }
  hx[0] = 2.0 * x[0] + x[1] + x[2] + x[3] + x[4];
  hx[1] = x[0] + 2.0 * x[1] + x[2] + x[3] + x[4];
  hx[2] = x[0] + x[1] + 2.0 * x[2] + x[3] + x[4];
  hx[3] = x[0] + x[1] + x[2] + 2.0 * x[3] + x[4];
  hx[4] = x[0] + x[1] + x[2] + x[3] + 2.0 * x[4];
} /* qphess */