/* nag_5d_shep_eval (e01tnc) Example Program.
 *
 * Copyright 2017 Numerical Algorithms Group.
 *
 * Mark 26.1, 2017.
 */

#include <stdio.h>
#include <nag.h>
#include <nag_stdlib.h>
#include <nage01.h>
#include <nagg05.h>
#include <math.h>

#ifdef __cplusplus
extern "C"
{
#endif
  static double NAG_CALL funct(double x[]);
#ifdef __cplusplus
}
#endif

#define X(I, J) x[I *5 + J]
#define XE(I, J) xe[I *5 + J]

int main(void)
{
  /* Scalars */
  Integer exit_status, i, m, n, nq, nw, liq, lrq, lstate, subid;
  Integer lseed = 1;
  double fun;
  Nag_BaseRNG genid;
  NagError fail;
  /* Arrays */
  double *f = 0, *q = 0, *qx = 0, *rq = 0, *xe = 0, *x = 0;
  Integer *iq = 0, *state = 0;
  Integer seed[1], seed2[1];

  exit_status = 0;

  INIT_FAIL(fail);

  printf("nag_5d_shep_eval (e01tnc) Example Program Results\n");

  /* Skip heading in data file */
  scanf("%*[^\n] ");

  /* Input the seeds. */
  scanf("%" NAG_IFMT "%" NAG_IFMT "%*[^\n] ", &seed[0], &seed2[0]);

  /* Choose the base generator */
  genid = Nag_Basic;
  subid = 0;

  /* Get the length of the state array */
  lstate = -1;
  nag_rand_init_repeatable(genid, subid, seed, lseed, state, &lstate, &fail);
  if (fail.code != NE_NOERROR) {
    printf("Error from nag_rand_init_repeatable (g05kfc).\n%s\n",
           fail.message);
    exit_status = 1;
    goto END;
  }

  /* Input the number of nodes. */
  scanf("%" NAG_IFMT "%*[^\n] ", &m);

  /* Allocate memory */
  lrq = 21 * m + 11;
  liq = 2 * m + 1;
  if (!(f = NAG_ALLOC(m, double)) ||
      !(x = NAG_ALLOC(m * 5, double)) ||
      !(rq = NAG_ALLOC(lrq, double)) ||
      !(iq = NAG_ALLOC(liq, Integer)) ||
      !(state = NAG_ALLOC(lstate, Integer)))
  {
    printf("Allocation failure\n");
    exit_status = -1;
    goto END;
  }

  /* Initialize the generator to a repeatable sequence */
  nag_rand_init_repeatable(genid, subid, seed, lseed, state, &lstate, &fail);
  if (fail.code != NE_NOERROR) {
    printf("Error from nag_rand_init_repeatable (g05kfc).\n%s\n",
           fail.message);
    exit_status = 1;
    goto END;
  }

  /* Generate the data points X */
  nag_rand_basic(m * 5, state, x, &fail);
  if (fail.code != NE_NOERROR) {
    printf("Error from nag_rand_basic (g05sac).\n%s\n", fail.message);
    exit_status = 1;
    goto END;
  }

  /* Evaluate F */
  for (i = 0; i < m; ++i) {
    f[i] = funct(&X(i, 0));
  }

  /* Generate the interpolant. */
  nq = 0;
  nw = 0;

  /* nag_5d_shep_interp (e01tmc).
   * Interpolating functions, modified Shepard's method, five
   * variables
   */
  nag_5d_shep_interp(m, x, f, nw, nq, iq, rq, &fail);
  if (fail.code != NE_NOERROR) {
    printf("Error from nag_5d_shep_interp (e01tmc).\n%s\n", fail.message);
    exit_status = 1;
    goto END;
  }

  /* Input the number of evaluation points. */
  scanf("%" NAG_IFMT "%*[^\n] ", &n);

  /* Allocate memory for nag_5d_shep_eval (e01tnc) */
  if (!(q = NAG_ALLOC(n, double)) ||
      !(qx = NAG_ALLOC(n * 5, double)) || !(xe = NAG_ALLOC(n * 5, double)))
  {
    printf("Allocation failure\n");
    exit_status = -1;
    goto END;
  }

  /* Generate repeatable evaluation points. */
  nag_rand_init_repeatable(genid, subid, seed2, lseed, state, &lstate, &fail);
  if (fail.code != NE_NOERROR) {
    printf("Error from nag_rand_init_repeatable (g05kfc).\n%s\n",
           fail.message);
    exit_status = 1;
    goto END;
  }
  nag_rand_basic(n * 5, state, xe, &fail);
  if (fail.code != NE_NOERROR) {
    printf("Error from nag_rand_basic (g05sac).\n%s\n", fail.message);
    exit_status = 1;
    goto END;
  }

  /* nag_5d_shep_eval (e01tnc).
   * Evaluate interpolant and first derivatives computed by
   * nag_5d_shep_interp (e01tmc).
   */
  fail.print = Nag_TRUE;
  nag_5d_shep_eval(m, x, f, iq, rq, n, xe, q, qx, &fail);
  if (fail.code != NE_NOERROR) {
    printf("Error from nag_5d_shep_eval (e01tnc).\n%s\n", fail.message);
    exit_status = 1;
    goto END;
  }

  printf("\n     i     f(x)      q(x)   |f(x)-Q(x)|\n");
  for (i = 0; i < n; ++i) {
    fun = funct(&XE(i, 0));
    printf("%6" NAG_IFMT "%10.4f%10.4f%10.4f\n", i, fun, q[i],
           fabs(fun - q[i]));
  }

END:
  NAG_FREE(f);
  NAG_FREE(q);
  NAG_FREE(qx);
  NAG_FREE(rq);
  NAG_FREE(xe);
  NAG_FREE(x);
  NAG_FREE(iq);
  NAG_FREE(state);

  return exit_status;
}

static double NAG_CALL funct(double x[])
{
  /* Scalars */
  double ret_val;

  ret_val = ((1.25 + cos(5.4 * x[4])) * cos(6.0 * x[0]) * cos(6.0 * x[1])
             * cos(6.0 * x[2])) / (6.0 + 6.0 * pow((3.0 * x[3] - 1.0), 2.0));
  return ret_val;
}