/* nag_opt_lsq_no_deriv (e04fcc) Example Program.
*
* Copyright 2014 Numerical Algorithms Group.
*
* Mark 2, 1991.
* Mark 7 revised, 2001.
* Mark 8 revised, 2004.
*
*/

#include <nag.h>
#include <stdio.h>
#include <string.h>
#include <nag_stdlib.h>
#include <math.h>
#include <nage04.h>
#include <nagx02.h>

#ifdef __cplusplus
extern "C" {
#endif
static void NAG_CALL lsqfun(Integer m, Integer n, const double x[],
double fvec[], Nag_Comm *comm);
#ifdef __cplusplus
}
#endif

#define MMAX 15
#define TMAX 3

/* Define a user structure template to store data in lsqfun. */
struct user
{
double y[MMAX];
double t[MMAX][TMAX];
};

int main(void)
{
const char  *optionsfile = "e04fcce.opt";
Integer     exit_status = 0;
Nag_Boolean print;
Integer     i, j, m, n, nt, tdfjac;
Nag_Comm    comm;
Nag_E04_Opt options;
double      *fjac = 0, fsumsq, *fvec = 0, *x = 0;
struct user s;
NagError    fail;

INIT_FAIL(fail);

printf("nag_opt_lsq_no_deriv (e04fcc) Example Program Results\n");
fflush(stdout);
scanf(" %*[^\n]"); /* Skip heading in data file */
n = 3;
m = 15;
if (m >= 1 && n <= m)
{
if (!(fjac = NAG_ALLOC(m*n, double)) ||
!(fvec = NAG_ALLOC(m, double)) ||
!(x = NAG_ALLOC(n, double)))
{
printf("Allocation failure\n");
exit_status = -1;
goto END;
}
tdfjac = n;
}
else
{
printf("Invalid m or n.\n");
exit_status = 1;
return exit_status;
}

* Observations t (j = 0, 1, 2) are held in s->t[i][j]
* (i = 0, 1, 2, . . .,  14)
*/
nt = 3;
for (i = 0; i < m; ++i)
{
scanf("%lf", &s.y[i]);
for (j = 0; j < nt; ++j) scanf("%lf", &s.t[i][j]);
}

/* Set up the starting point */
x[0] = 0.5;
x[1] = 1.0;
x[2] = 1.5;

/* nag_opt_init (e04xxc).
* Initialization function for option setting
*/
nag_opt_init(&options); /* Initialise options structure */
/* Set one option directly. */
/* nag_machine_precision (x02ajc).
* The machine precision
*/
options.optim_tol = 10.0*sqrt(nag_machine_precision);

/* Read remaining option values from file */
print = Nag_FALSE;
* Read options from a text file
*/
nag_opt_read("e04fcc", optionsfile, &options, print, "stdout", &fail);
if (fail.code != NE_NOERROR)
{
exit_status = 1;
goto END;
}

/* Assign address of user defined structure to
* comm.p for communication to lsqfun().
*/
comm.p = (Pointer)&s;

/* nag_opt_lsq_no_deriv (e04fcc), see above. */
nag_opt_lsq_no_deriv(m, n, lsqfun, x, &fsumsq, fvec, fjac, tdfjac,
&options, &comm, &fail);
if (fail.code != NE_NOERROR)
{
printf("Error/Warning from nag_opt_lsq_no_deriv (e04fcc).\n%s\n",
fail.message);
if (fail.code != NW_COND_MIN)
exit_status = 1;
}

/* Free memory allocated to pointers s and v */
/* nag_opt_free (e04xzc).
* Memory freeing function for use with option setting
*/
nag_opt_free(&options, "all", &fail);
if (fail.code != NE_NOERROR)
{
printf("Error from nag_opt_free (e04xzc).\n%s\n", fail.message);
exit_status = 2;
goto END;
}
END:
NAG_FREE(fjac);
NAG_FREE(fvec);
NAG_FREE(x);

return exit_status;
}

static void NAG_CALL lsqfun(Integer m, Integer n, const double x[],
double fvec[], Nag_Comm *comm)
{
/* Function to evaluate the residuals.
*
* To avoid the use of a global varibale this example assigns the address
* of a user defined structure to comm.p in the main program (where the
* data was also read in).
* The address of this structure is recovered in each call to lsqfun()
* from comm->p and the structure used in the calculation of the residuals.
*/

Integer     i;
struct user *s = (struct user *) comm->p;

for (i = 0; i < m; ++i)
fvec[i] = x[0] + s->t[i][0] /
(x[1]*s->t[i][1] + x[2]*s->t[i][2]) - s->y[i];
} /* lsqfun */