/* nag_nearest_correlation_bounded (g02abc) Example Program.
 *
 * Copyright 2014 Numerical Algorithms Group.
 *
 * Mark 23, 2011.
 */

#include <nag.h>
#include <nag_stdlib.h>
#include <nagf08.h>
#include <nagg02.h>
#include <nagx04.h>

int main(void)
{

  /* Scalars */
  Integer               exit_status = 0;
  double                alpha, errtol, nrmgrd;
  Integer               feval, i, iter, j, maxit, maxits, n, pdeig, pdg, pdx;

  /* Arrays */
  char                  nag_enum_arg[100];
  double                *eig = 0, *g = 0, *w = 0, *x = 0;

  /* Nag Types */
  Nag_OrderType         order;
  Nag_NearCorr_ProbType opt;
  NagError              fail;

  INIT_FAIL(fail);

#ifdef NAG_COLUMN_MAJOR
#define G(I, J) g[(J-1)*pdg + I-1]
#define X(I, J) x[(J-1)*pdx + I-1]
  order = Nag_ColMajor;
#else
#define G(I, J) g[(I-1)*pdg + J-1]
#define X(I, J) x[(I-1)*pdx + J-1]
  order = Nag_RowMajor;
#endif

  /* Output preamble */
  printf("nag_nearest_correlation_bounded (g02abc)");
  printf(" Example Program Results\n\n");
  fflush(stdout);

  /* Skip heading in data file */
  scanf("%*[^\n] ");
  /* Read in the problem size, opt and alpha */
  scanf("%ld", &n);
  scanf("%39s", nag_enum_arg);
  /*
   * nag_enum_name_to_value (x04nac).
   * Converts NAG enum member name to value
   */
  opt = (Nag_NearCorr_ProbType) nag_enum_name_to_value(nag_enum_arg);
  scanf("%lf%*[^\n]", &alpha);

  pdg = n;
  pdx = n;
  if( order == Nag_ColMajor)
    pdeig = 1;
  else
    pdeig = n;

  if (
      !(g = NAG_ALLOC((pdg)*(n), double)) ||
      !(w = NAG_ALLOC((n), double)) ||
      !(x = NAG_ALLOC((pdx)*(n), double)) ||
      !(eig = NAG_ALLOC((n), double))
      )
    {
      printf("Allocation failure\n");
      exit_status = -1;
      goto END;
    }

  /* Read in the matrix g */
  for (i = 1; i <= n; i++)
    for (j = 1; j <= n; j++)
      scanf("%lf", &G(i, j));
  scanf("%*[^\n] ");

  /* Read in the vector w */
  for (i = 0; i < n; i++)
    scanf("%lf", &w[i]);
  scanf("%*[^\n] ");

  /* Use the defaults for errtol, maxits and maxit */
  errtol = 0.0;
  maxits = 0;
  maxit = 0;

  /*
   * nag_nearest_correlation_bounded (g02abc).
   * Computes the nearest correlation matrix incorporating weights
   * and/or bounds
   */
  nag_nearest_correlation_bounded(order, g, pdg, n, opt, alpha, w, errtol,
                                  maxits, maxit, x, pdx, &iter, &feval,
                                  &nrmgrd, &fail);
  if (fail.code != NE_NOERROR)
    {
      printf("%s\n", fail.message);
      exit_status = 1;
      goto END;
    }

  /*
   * nag_gen_real_mat_print (x04cac).
   * Print real general matrix (easy-to-use)
   */
  nag_gen_real_mat_print(order, Nag_GeneralMatrix, Nag_NonUnitDiag, n, n, x,
                         pdx, "Nearest Correlation Matrix x", NULL, &fail);
  if (fail.code != NE_NOERROR)
    {
      printf("%s\n", fail.message);
      exit_status = 1;
      goto END;
    }
  printf("\nNumber of Newton steps taken: %11ld\n", iter);
  printf("Number of function evaluations: %9ld\n\n", feval);
  printf("alpha: %37.3f \n\n", alpha);
  fflush(stdout);

  /* nag_dsyev (f08fac).
   * Computes all eigenvalues and, optionally, eigenvectors of a real
   * symmetric matrix
   */
  nag_dsyev(order, Nag_EigVals, Nag_Upper, n, x, pdx, eig, &fail);
  if (fail.code != NE_NOERROR)
    {
      printf("%s\n", fail.message);
      exit_status = 1;
      goto END;
    }

  /* nag_gen_real_mat_print (x04cac).
   * Print real general matrix (easy-to-use)
   */
  nag_gen_real_mat_print(order, Nag_GeneralMatrix, Nag_NonUnitDiag, 1, n,
                         eig, pdeig, "Eigenvalues of x", NULL, &fail);
  if (fail.code != NE_NOERROR)
    {
      printf("%s\n", fail.message);
      exit_status = 1;
    }

 END:
  NAG_FREE(eig);
  NAG_FREE(g);
  NAG_FREE(w);
  NAG_FREE(x);
  return exit_status;
}