/* nag_opt_lsq_deriv (e04gbc) Example Program. * * Copyright 1991 Numerical Algorithms Group. * * Mark 2, 1991. * Mark 7 revised, 2001. * Mark 7a revised, 2003. * Mark 8 revised, 2004. * */ #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 int ex1(void); static int 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) { Integer exit_status_ex1=0; Integer exit_status_ex2=0; /* 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("nag_opt_lsq_deriv (e04gbc) Example Program Results.\n"); Vscanf(" %*[^\n]"); /* Skip heading in data file */ exit_status_ex1 = ex1(); exit_status_ex2 = ex2(); return exit_status_ex1 == 0 && exit_status_ex2 == 0 ? 0 : 1; } static int ex1(void) { Integer exit_status=0, m, n, tdj; NagError fail; double *fjac=0, fsumsq, *fvec=0, *x=0; INIT_FAIL(fail); Vprintf("\nnag_opt_lsq_deriv (e04gbc) example 1: no option setting.\n"); Vscanf(" %*[^\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)) ) { Vprintf("Allocation failure\n"); exit_status = -1; goto END; } } else { Vprintf("Invalid m or n.\n"); exit_status = 1; return exit_status; } tdj = n; /* Set up the starting point */ x[0] = 0.5; x[1] = 1.0; x[2] = 1.5; /* Call the optimization routine */ /* nag_opt_lsq_deriv (e04gbc). * Unconstrained nonlinear least-squares (first derivatives * required) */ nag_opt_lsq_deriv(m, n, lsqfun1, x, &fsumsq, fvec, fjac, tdj, E04_DEFAULT, NAGCOMM_NULL, &fail); if (fail.code != NE_NOERROR) { Vprintf("Error/Warning from nag_opt_lsq_deriv (e04gbc).\n%s\n", fail.message); if (fail.code != NW_COND_MIN) exit_status = 1; goto END; } END: if (fjac) NAG_FREE(fjac); if (fvec) NAG_FREE(fvec); if (x) NAG_FREE(x); return exit_status; } /* 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 int ex2(void) { Nag_Boolean print; Integer exit_status=0, i, j, m, n, nt, tdfjac; NagError fail; Nag_Comm comm; Nag_E04_Opt options; double *fjac=0, fsumsq, *fvec=0, *x=0; struct user s; INIT_FAIL(fail); Vprintf("\n\nnag_opt_lsq_deriv (e04gbc) example 2: using option setting.\n"); Vscanf(" %*[^\n]"); /* Skip heading in data file */ n = 3; m = 15; nt = 3; if ( m >=1 && n<=m) { if ( !( fjac = NAG_ALLOC(m*n, double)) || !( fvec = NAG_ALLOC(m, double)) || !( x = NAG_ALLOC(n, double)) ) { Vprintf("Allocation failure\n"); exit_status = -1; goto END; } tdfjac = n; } else { Vprintf("Invalid m or n.\n"); exit_status = 1; return exit_status; } /* 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 */ print = Nag_TRUE; /* nag_opt_init (e04xxc). * Initialization function for option setting */ nag_opt_init(&options); /* nag_opt_read (e04xyc). * Read options from a text file */ nag_opt_read("e04gbc", "stdin", &options, print, "stdout", &fail); if (fail.code != NE_NOERROR) { Vprintf("Error from nag_opt_read (e04xyc).\n%s\n", fail.message); exit_status = 1; goto END; } /* Assign address of user defined structure to * comm.p for communication to lsqfun2(). */ comm.p = (Pointer)&s; /* Call the optimization routine */ /* nag_opt_lsq_deriv (e04gbc), see above. */ nag_opt_lsq_deriv(m, n, lsqfun2, x, &fsumsq, fvec, fjac, tdfjac, &options, &comm, &fail); if (fail.code != NE_NOERROR) { Vprintf("Error/Warning from nag_opt_lsq_deriv (e04gbc).\n%s\n", fail.message); if (fail.code != NW_COND_MIN) exit_status = 1; } /* Free memory allocated by nag_opt_lsq_deriv (e04gbc) 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) { Vprintf("Error from nag_opt_free (e04xzc).\n%s\n", fail.message); exit_status = 2; } END: if (fjac) NAG_FREE(fjac); if (fvec) NAG_FREE(fvec); if (x) NAG_FREE(x); return exit_status; } /* 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 */