/* nag_opt_lsq_deriv (e04gbc) Example Program * * Copyright 1991 Numerical Algorithms Group. * * Mark 2, 1991. * Mark 7 revised, 2001. * */ #include #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif static void lsqfun1(Integer m, Integer n, double x[], double fvec[], double fjac[], Integer tdj, Nag_Comm *comm); static void lsqfun2(Integer m, Integer n, double x[], double fvec[], double fjac[], Integer tdj, Nag_Comm *comm); #ifdef __cplusplus } #endif static void ex1(void); static void ex2(void); #define MMAX 15 #define NMAX 3 #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) { /* Two examples are called, ex1() which uses the * default settings to solve the problem and * ex2() which solves the same problem with * some optional parameters set by the user. */ Vprintf("e04gbc Example Program Results.\n"); Vscanf(" %*[^\n]"); /* Skip heading in data file */ ex1(); ex2(); return EXIT_SUCCESS; } static void ex1(void) { double fjac[MMAX][NMAX], fvec[MMAX], x[NMAX]; Integer m, n, tdj; double fsumsq; static NagError fail; Vprintf("\ne04gbc example 1: no option setting.\n"); Vscanf(" %*[^\n]"); /* Skip heading in data file */ n = 3; m = 15; tdj = NMAX; /* Set up the starting point */ x[0] = 0.5; x[1] = 1.0; x[2] = 1.5; /* Call the optimization routine */ fail.print = TRUE; e04gbc(m, n, lsqfun1, x, &fsumsq, fvec, &fjac[0][0], tdj, E04_DEFAULT, NAGCOMM_NULL, &fail); if (fail.code != NE_NOERROR && fail.code != NW_COND_MIN) exit(EXIT_FAILURE); } /* ex1 */ static void lsqfun1(Integer m, Integer n, double x[], double fvec[], double fjac[], Integer tdj, Nag_Comm *comm) { /* Function to evaluate the residuals and their 1st derivatives * in example 1. * * This function is also suitable for use when Nag_Lin_NoDeriv is * specified for linear minimization instead of the default of * Nag_Lin_Deriv, since it can deal with comm->flag = 0 or 1 as * well comm->flag = 2. * * In this example a static variable is used to hold the * initial observations. The data is read into the structure * gs on the first call to lsqfun1(), it could alternatively * be read in from within int main(void). */ #define FJAC(I,J) fjac[(I)*tdj + (J)] Integer i, j, nt; double denom, dummy; static struct user gs; if (comm->first) { /* First call to lsqfun(), read data into structure. * Observations t (j = 0, 1, 2) are held in gs.t[i][j] * (i = 0, 1, 2, . . . , 14) */ nt = 3; for (i = 0; i < m; ++i) { Vscanf("%lf", &gs.y[i]); for (j = 0; j < nt; ++j) Vscanf("%lf", &gs.t[i][j]); } } for (i = 0; i < m; ++i) { denom = x[1]*gs.t[i][1] + x[2]*gs.t[i][2]; if (comm->flag != 1) fvec[i] = x[0] + gs.t[i][0]/denom - gs.y[i]; if (comm->flag != 0) { FJAC(i,0) = 1.0; dummy = -1.0 / (denom * denom); FJAC(i,1) = gs.t[i][0]*gs.t[i][1]*dummy; FJAC(i,2) = gs.t[i][0]*gs.t[i][2]*dummy; } } } /* lsqfun1 */ static void ex2(void) { double fjac[MMAX][NMAX], fvec[MMAX], x[NMAX]; Integer i, j, m, n, nt, tdj; double fsumsq; Boolean print; Nag_E04_Opt options; Nag_Comm comm; static NagError fail, fail2; struct user s; Vprintf("\n\ne04gbc example 2: using option setting.\n"); Vscanf(" %*[^\n]"); /* Skip heading in data file */ n = 3; m = 15; tdj = NMAX; nt = 3; /* Read data into structure. * 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) { Vscanf("%lf", &s.y[i]); for (j = 0; j < nt; ++j) Vscanf("%lf", &s.t[i][j]); } /* Set up the starting point */ x[0] = 0.5; x[1] = 1.0; x[2] = 1.5; /* Initialise options structure and read option values from file */ fail.print = TRUE; print = TRUE; e04xxc(&options); e04xyc("e04gbc", "stdin", &options, print, "stdout", &fail); if (fail.code != NE_NOERROR) exit(EXIT_FAILURE); /* Assign address of user defined structure to * comm.p for communication to lsqfun2(). */ comm.p = (Pointer)&s; /* Call the optimization routine */ e04gbc(m, n, lsqfun2, x, &fsumsq, fvec, &fjac[0][0], tdj, &options, &comm, &fail); /* Free memory allocated by e04gbc to pointers s and v */ fail2.print = TRUE; e04xzc(&options, "all", &fail2); if ((fail.code != NE_NOERROR && fail.code != NW_COND_MIN) || fail2.code != NE_NOERROR) exit(EXIT_FAILURE); } /* ex2 */ static void lsqfun2(Integer m, Integer n, double x[], double fvec[], double fjac[], Integer tdj, Nag_Comm *comm) { /* Function to evaluate the residuals and their 1st derivatives * in example 2. * * This function is also suitable for use when Nag_Lin_NoDeriv is specified * for linear minimization instead of the default of Nag_Lin_Deriv, * since it can deal with comm->flag = 0 or 1 as well as comm->flag = 2. * * 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 lsqfun2() * from comm->p and the structure used in the calculation of the residuals. */ #define FJAC(I,J) fjac[(I)*tdj + (J)] Integer i; double denom, dummy; struct user *s = (struct user *)comm->p; for (i = 0; i < m; ++i) { denom = x[1]*s->t[i][1] + x[2]*s->t[i][2]; if (comm->flag != 1) fvec[i] = x[0] + s->t[i][0]/denom - s->y[i]; if (comm->flag != 0) { FJAC(i,0) = 1.0; dummy = -1.0 / (denom * denom); FJAC(i,1) = s->t[i][0]*s->t[i][1]*dummy; FJAC(i,2) = s->t[i][0]*s->t[i][2]*dummy; } } } /* lsqfun2 */