1677 lines
50 KiB
C
1677 lines
50 KiB
C
|
|
/* Concatenated dnsq code */
|
|
|
|
/*
|
|
* This concatenation, translation to C and modifications,
|
|
* Copyright 1998 Graeme Gill
|
|
* All rights reserved.
|
|
*
|
|
* This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
|
|
* see the License.txt file for licencing details.
|
|
*/
|
|
|
|
#include "numsup.h"
|
|
#include "dnsq.h" /* Public interface definitions */
|
|
|
|
#undef DEBUG
|
|
|
|
typedef long int abool;
|
|
#ifndef TRUE
|
|
# define FALSE (0)
|
|
# define TRUE (!FALSE)
|
|
#endif
|
|
|
|
#ifndef min
|
|
#define min(a,b) ((a) <= (b) ? (a) : (b))
|
|
#endif
|
|
#ifndef max
|
|
#define max(a,b) ((a) >= (b) ? (a) : (b))
|
|
#endif
|
|
#ifndef fabs
|
|
#define fabs(x) ((x) >= 0.0 ? (x) : -(x))
|
|
#endif
|
|
|
|
/* Forward difference jacobian approximation */
|
|
static int dfdjc1(
|
|
void *fdata,
|
|
int (*fcn)(void *fdata, int n, double *x, double *fvec, int iflag),
|
|
int n, double *x, double * fvec, double *fjac,
|
|
int ldfjac, int ml, int mu,
|
|
double epsfcn, double *wa1, double *wa2);
|
|
|
|
/* QR factorization */
|
|
static int dqrfac(int m, int n, double *a, int lda,
|
|
abool pivot, int *ipvt, double *sigma,
|
|
double *acnorm, double *wa);
|
|
|
|
/* Use QR decomposition to form the orthogonal matrix */
|
|
static int dqform(int m, int n, double *q, int ldq, double *wa);
|
|
|
|
/* QR decomposition update */
|
|
static int d1updt(int m, int n, double *s,
|
|
double *u, double *v, double *w);
|
|
|
|
/* Jacobian rotation, called by QR update */
|
|
static int d1mpyq(int m, int n, double *a, int lda,
|
|
double *v, double *w);
|
|
|
|
/* Compute norm of a vector */
|
|
static double denorm(int n, double *x);
|
|
|
|
/* Line search */
|
|
static int ddoglg(int n, double *r, double *diag, double *qtb,
|
|
double delta, double *x, double *wa1, double *wa2);
|
|
|
|
/***************************************************************/
|
|
|
|
/*
|
|
* A simplified interface to dnsq().
|
|
*/
|
|
|
|
int dnsqe(
|
|
void *fdata, /* Opaque pointer to pass to fcn() and jac() */
|
|
int (*fcn)(void *fdata, int n, double *x, double *fvec, int iflag),
|
|
/* Pointer to function we are solving */
|
|
int (*jac)(void *fdata, int n, double *x, double *fvec, double **fjac),
|
|
/* Optional function to compute jacobian, NULL if not used */
|
|
int n, /* Number of functions and variables */
|
|
double x[], /* Initial solution estimate, RETURNs final solution */
|
|
double ss, /* Initial search area */
|
|
double fvec[], /* Array that will be RETURNed with thefunction values at the solution */
|
|
double dtol, /* Desired delta tollerance of the solution */
|
|
double atol, /* Desired absolute tollerance of the solution */
|
|
int maxfev, /* Maximum number of function calls. set to 0 for automatic */
|
|
int nprint /* Turn on debugging printouts from func() every nprint itterations */
|
|
) {
|
|
int info = 0; /* Return status */
|
|
|
|
int nfev, njev;
|
|
int i,j, index, ml, lr, mu;
|
|
double epsfcn = ss * ss; /* Jacobian estimate step */
|
|
double factor = ss; /* Initial step size */
|
|
double maxstep = 0.0; /* Subsequent step size (not working ??) */
|
|
|
|
if (maxfev <= 0) {
|
|
maxfev = (n + 1) * 100;
|
|
if (jac == NULL)
|
|
maxfev <<= 1;
|
|
}
|
|
ml = n - 1; /* number of subdiagonals within the band of the Jacobian matrix. */
|
|
mu = n - 1; /* number of superdiagonals within the band of the Jacobian matrix. */
|
|
|
|
lr = n * (n + 1) / 2;
|
|
index = n * 6 + lr;
|
|
|
|
/* Call dnsq. */
|
|
info = dnsq(fdata, fcn, jac, NULL, 0,
|
|
n, &x[0], &fvec[0], dtol, atol,
|
|
maxfev, ml, mu, epsfcn, NULL, factor, maxstep, nprint,
|
|
&nfev, &njev);
|
|
|
|
if (info == 5)
|
|
info = 4;
|
|
if (info == 0)
|
|
warning("dnsqe: invalid input parameter.");
|
|
|
|
return info;
|
|
} /* dnsqe */
|
|
|
|
|
|
|
|
/***************************************************************/
|
|
/*
|
|
* Library: SLATEC
|
|
* Category: F2A
|
|
* Type: Double precision (SNSQE-S, DNSQE-D)
|
|
* Keywords easy-to-use, nonlinear square system,
|
|
* powell hybrid method, zeros
|
|
* Author: Hiebert, K. L. (SNLA)
|
|
* Translated to C by f2c and Graeme W. Gill
|
|
*
|
|
* 1. Purpose.
|
|
*
|
|
* The purpose of DNSQ is to find a zero of a system of N nonlinear
|
|
* functions in N variables by a modification of the Powell
|
|
* hybrid method. The user must provide a subroutine which
|
|
* calculates the functions. The user has the option of either to
|
|
* provide a subroutine which calculates the Jacobian or to let the
|
|
* code calculate it by a forward-difference approximation.
|
|
* This code is the combination of the MINPACK codes (Argonne)
|
|
* HYBRD and HYBRDJ.
|
|
*
|
|
* 2. Subroutine and Type Statements.
|
|
*
|
|
* SUBROUTINE DNSQ(FCN,JAC,N,X,FVEC,FJAC,LDFJAC,XTOL,MAXFEV,
|
|
* ML,MU,EPSFCN,DIAG,MODE,FACTOR,NPRINT,INFO,NFEV,
|
|
* NJEV,R,LR,QTF,WA1,WA2,WA3,WA4)
|
|
* INTEGER N,MAXFEV,ML,MU,MODE,NPRINT,INFO,NFEV,LDFJAC,NJEV,LR
|
|
* DOUBLE PRECISION XTOL,EPSFCN,FACTOR
|
|
* DOUBLE PRECISION
|
|
* X(N),FVEC(N),DIAG(N),FJAC(LDFJAC,N),R(LR),QTF(N),
|
|
* WA1(N),WA2(N),WA3(N),WA4(N)
|
|
* EXTERNAL FCN,JAC
|
|
*
|
|
* 3. Parameters.
|
|
*
|
|
* Parameters designated as input parameters must be specified on
|
|
* entry to DNSQ and are not changed on exit, while parameters
|
|
* designated as output parameters need not be specified on entry
|
|
* and are set to appropriate values on exit from DNSQ.
|
|
*
|
|
* fcn() is the name of the user-supplied subroutine which calculates
|
|
* the functions. fcn() must be declared in an external statement
|
|
* in the user calling program, and should be written as follows.
|
|
*
|
|
* int fcn(
|
|
* void *fdata,
|
|
* int n,
|
|
* double *x,
|
|
* double *fvec,
|
|
* int iflag);
|
|
* {
|
|
* calculate the functions at x and
|
|
* return this vector in fvec.
|
|
* print out vector if iflag == 0
|
|
* return 0 (or < 0 to abort)
|
|
* }
|
|
* The value 0 should be returned fcn() unless the
|
|
* user wants to terminate execution of DNSQ. In this case
|
|
* return a negative integer.
|
|
*
|
|
* jac() is the name of the user-supplied subroutine which calculates
|
|
* the Jacobian. If jac!=NULL, then jac() must be declared in an
|
|
* external statement in the user calling program, and should be
|
|
* written as follows.
|
|
*
|
|
* int jac(
|
|
* void *fdata,
|
|
* int n,
|
|
* double *x,
|
|
* double *fvec,
|
|
* double **fjac,
|
|
* {
|
|
* Calculate the Jacobian at x and return this
|
|
* matrix in fjac. fvec contains the function
|
|
* values at x and should not be altered.
|
|
* return 0 (or < 0 to abort)
|
|
* }
|
|
* The value 0 should be returned jac() unless the
|
|
* user wants to terminate execution of DNSQ. In this case
|
|
* return a negative integer.
|
|
*
|
|
* If jac == NULL, then the code will approximate the
|
|
* Jacobian by forward-differencing.
|
|
*
|
|
* double **sjac;
|
|
* sjac is an optional n by n matrix that can hold an initial
|
|
* jacobian matrix that will be used in preference to calling the jac()
|
|
* function, or to using forward differencing. If the array is provided,
|
|
* it will also contain the last jacobian matrix used before exiting.
|
|
* If this array is not used, it should be set to NULL.
|
|
*
|
|
* int startsjac;
|
|
* styatsjac is a flag, that when set to non-zero, will cause the
|
|
* sjac[] array to be used as the initial jacobian matrix, in preference
|
|
* to calling the jac() function, or to using forward differencing.
|
|
*
|
|
* n is a positive integer input variable set to the number of
|
|
* functions and variables.
|
|
*
|
|
* x is an array of length n. On input x must contain an initial
|
|
* estimate of the solution vector. On output x contains the
|
|
* final estimate of the solution vector.
|
|
*
|
|
* fvec is an output array of length n which contains the functions
|
|
* evaluated at the output x.
|
|
*
|
|
* fjac is an output N by N array which contains the orthogonal
|
|
* matrix Q produced by the QR factorization of the final
|
|
* approximate Jacobian.
|
|
*
|
|
* ldfjac is a positive integer input variable not less than n
|
|
* which specifies the leading dimension of the array fjac.
|
|
*
|
|
* dtol is a nonnegative input variable. Termination occurs when
|
|
* the relative error between two consecutive iterates is at most
|
|
* dtol. Therefore, dtol measures the relative error desired in
|
|
* the approximate solution. Section 4 contains more details
|
|
* about dtol.
|
|
*
|
|
* tol is a nonnegative input variable. Termination occurs when
|
|
* the value of all the function values falls below this threshold.
|
|
* Termination occurs when either the dtol or tol condition is met.
|
|
*
|
|
* maxfev is a positive integer input variable. Termination occurs
|
|
* when the number of calls to fcn is at least maxfev by the end
|
|
* of an iteration.
|
|
*
|
|
* ml is a nonnegative integer input variable which specifies the
|
|
* number of subdiagonals within the band of the Jacobian matrix.
|
|
* If the Jacobian is not banded or jac!=null, set ml to at
|
|
* least n - 1.
|
|
*
|
|
* mu is a nonnegative integer input variable which specifies the
|
|
* number of superdiagonals within the band of the Jacobian
|
|
* matrix. If the Jacobian is not banded or jac!=null, set mu to at
|
|
* least n - 1.
|
|
*
|
|
* epsfcn is an input variable used in determining a suitable step
|
|
* for the forward-difference approximation. This approximation
|
|
* assumes that the relative errors in the functions are of the
|
|
* order of epsfcn. If epsfcn is less than the machine
|
|
* precision, it is assumed that the relative errors in the
|
|
* functions are of the order of the machine precision. If
|
|
* jac!=null, then epsfcn can be ignored (treat it as a dummy
|
|
* argument).
|
|
*
|
|
* diag is an array of length n. If MODE = 1 (see below), diag is
|
|
* internally set. If mode = 2, diag must contain positive
|
|
* entries that serve as implicit (multiplicative) scale factors
|
|
* for the variables.
|
|
*
|
|
* mode is an integer input variable. If mode = 1, the variables
|
|
* will be scaled internally. If mode = 2, the scaling is
|
|
* specified by the input diag. Other values of mode are
|
|
* equivalent to mode = 1.
|
|
*
|
|
* factor is a positive input variable used in determining the
|
|
* initial step bound. This bound is set to the product of
|
|
* factor and the Euclidean norm of diag*x if nonzero, or else to
|
|
* factor itself. In most cases factor should lie in the
|
|
* interval (.1,100.). 100. is a generally recommended value.
|
|
*
|
|
* nprint is an integer input variable that enables controlled
|
|
* printing of iterates if it is positive. In this case, fcn is
|
|
* called with iflag = 0 at the beginning of the first iteration
|
|
* and every nprint iterations thereafter and immediately prior
|
|
* to return, with x and fvec available for printing. Appropriate
|
|
* print statements must be added to fcn(see example). If nprint
|
|
* is not positive, no special calls of fcn with iflag = 0 are
|
|
* made.
|
|
*
|
|
* info is an integer output variable. If the user has terminated
|
|
* execution, info is set to the (negative) value of iflag. See
|
|
* description of fcn and jac. Otherwise, INFO is set as follows.
|
|
*
|
|
* INFO = 0 Improper input parameters.
|
|
*
|
|
* INFO = 1 Relative error between two consecutive iterates is
|
|
* at most XTOL. Normal sucessful return value.
|
|
*
|
|
* INFO = 2 Number of calls to FCN has reached or exceeded
|
|
* MAXFEV.
|
|
*
|
|
* INFO = 3 XTOL is too small. No further improvement in the
|
|
* approximate solution X is possible.
|
|
*
|
|
* INFO = 4 Iteration is not making good progress, as measured
|
|
* by the improvement from the last five Jacobian
|
|
* evaluations.
|
|
*
|
|
* INFO = 5 Iteration is not making good progress, as measured
|
|
* by the improvement from the last ten iterations.
|
|
* Return value if no zero can be found from this starting
|
|
* point.
|
|
*
|
|
* Sections 4 and 5 contain more details about INFO.
|
|
*
|
|
* nfev is an integer output variable set to the number of calls to
|
|
* fcn.
|
|
*
|
|
* njev is an integer output variable set to the number of calls to
|
|
* jac. (If jac==null, then njev is set to zero.)
|
|
*
|
|
* 4. Successful completion.
|
|
*
|
|
* The accuracy of DNSQ is controlled by the convergence parameter
|
|
* XTOL. This parameter is used in a test which makes a comparison
|
|
* between the approximation X and a solution XSOL. DNSQ
|
|
* terminates when the test is satisfied. If the convergence
|
|
* parameter is less than the machine precision (as defined by the
|
|
* function D1MACH(4)), then DNSQ only attempts to satisfy the test
|
|
* defined by the machine precision. Further progress is not
|
|
* usually possible.
|
|
*
|
|
* The test assumes that the functions are reasonably well behaved,
|
|
* and, if the Jacobian is supplied by the user, that the functions
|
|
* and the Jacobian are coded consistently. If these conditions
|
|
* are not satisfied, then DNSQ may incorrectly indicate
|
|
* convergence. The coding of the Jacobian can be checked by the
|
|
* subroutine DCKDER. If the Jacobian is coded correctly or JAC==NULL,
|
|
* then the validity of the answer can be checked, for example, by
|
|
* rerunning DNSQ with a tighter tolerance.
|
|
*
|
|
* Convergence Test. If DENORM(Z) denotes the Euclidean norm of a
|
|
* vector Z and D is the diagonal matrix whose entries are
|
|
* defined by the array DIAG, then this test attempts to
|
|
* guarantee that
|
|
*
|
|
* DENORM(D*(X-XSOL)) .LE. XTOL*DENORM(D*XSOL).
|
|
*
|
|
* If this condition is satisfied with XTOL = 10**(-K), then the
|
|
* larger components of D*X have K significant decimal digits and
|
|
* INFO is set to 1. There is a danger that the smaller
|
|
* components of D*X may have large relative errors, but the fast
|
|
* rate of convergence of DNSQ usually avoids this possibility.
|
|
*
|
|
* Unless high precision solutions are required, the recommended
|
|
* value for XTOL is the square root of the machine precision.
|
|
*
|
|
*
|
|
* 5. Unsuccessful Completion.
|
|
*
|
|
* Unsuccessful termination of DNSQ can be due to improper input
|
|
* parameters, arithmetic interrupts, an excessive number of
|
|
* function evaluations, or lack of good progress.
|
|
*
|
|
* Improper Input Parameters. INFO is set to 0 if
|
|
* N .LE. 0, or LDFJAC .LT. N, or
|
|
* XTOL .LT. 0.E0, or MAXFEV .LE. 0, or ML .LT. 0, or MU .LT. 0,
|
|
* or FACTOR .LE. 0.E0, or LR .LT. (N*(N+1))/2.
|
|
*
|
|
* Arithmetic Interrupts. If these interrupts occur in the FCN
|
|
* subroutine during an early stage of the computation, they may
|
|
* be caused by an unacceptable choice of X by DNSQ. In this
|
|
* case, it may be possible to remedy the situation by rerunning
|
|
* DNSQ with a smaller value of FACTOR.
|
|
*
|
|
* Excessive Number of Function Evaluations. A reasonable value
|
|
* for MAXFEV is 100*(N+1) for JAC!=NULL and 200*(N+1) for JAC==NULL.
|
|
*
|
|
* If the number of calls to FCN reaches MAXFEV, then this
|
|
* indicates that the routine is converging very slowly as
|
|
* measured by the progress of FVEC, and INFO is set to 2. This
|
|
*
|
|
* situation should be unusual because, as indicated below, lack
|
|
* of good progress is usually diagnosed earlier by DNSQ,
|
|
* causing termination with info = 4 or INFO = 5.
|
|
*
|
|
* Lack of Good Progress. DNSQ searches for a zero of the system
|
|
*
|
|
* by minimizing the sum of the squares of the functions. In so
|
|
* doing, it can become trapped in a region where the minimum
|
|
* does not correspond to a zero of the system and, in this
|
|
* situation, the iteration eventually fails to make good
|
|
* progress. In particular, this will happen if the system does
|
|
* not have a zero. If the system has a zero, rerunning DNSQ
|
|
* from a different starting point may be helpful.
|
|
*
|
|
*
|
|
* 6. Characteristics of The Algorithm.
|
|
*
|
|
* DNSQ is a modification of the Powell Hybrid method. Two of its
|
|
* main characteristics involve the choice of the correction as a
|
|
* convex combination of the Newton and scaled gradient directions,
|
|
* and the updating of the Jacobian by the rank-1 method of
|
|
* Broyden. The choice of the correction guarantees (under
|
|
* reasonable conditions) global convergence for starting points
|
|
* far from the solution and a fast rate of convergence. The
|
|
* Jacobian is calculated at the starting point by either the
|
|
* user-supplied subroutine or a forward-difference approximation,
|
|
* but it is not recalculated until the rank-1 method fails to
|
|
* produce satisfactory progress.
|
|
*
|
|
* Timing. The time required by DNSQ to solve a given problem
|
|
* depends on N, the behavior of the functions, the accuracy
|
|
* requested, and the starting point. The number of arithmetic
|
|
* operations needed by DNSQ is about 11.5*(N**2) to process
|
|
* each evaluation of the functions (call to FCN) and 1.3*(N**3)
|
|
* to process each evaluation of the Jacobian (call to JAC,
|
|
* if JAC!=NULL). Unless FCN and JAC can be evaluated quickly,
|
|
* the timing of DNSQ will be strongly influenced by the time
|
|
* spent in FCN and JAC.
|
|
*
|
|
* Storage. DNSQ requires (3*N**2 + 17*N)/2 single precision
|
|
* storage locations, in addition to the storage required by the
|
|
* program. There are no internally declared storage arrays.
|
|
*
|
|
* References: M. J. D. Powell, A hybrid method for nonlinear equa-
|
|
* tions. In Numerical Methods for Nonlinear Algebraic
|
|
* Equations, P. Rabinowitz, Editor. Gordon and Breach,
|
|
* 1988.
|
|
*
|
|
* Routines called: D1MPYQ, D1UPDT, DDOGLG, DENORM, DFDJC1, DQFORM, DQRFAC
|
|
*
|
|
* Revision history: (YYMMDD)
|
|
* 800301 DATE WRITTEN
|
|
* 890531 Changed all specific intrinsics to generic. (WRB)
|
|
* 890831 Modified array declarations. (WRB)
|
|
* 890831 REVISION DATE from Version 3.2
|
|
* 891214 Prologue converted to Version 4.0 format. (BAB)
|
|
* 900315 CALLs to XERROR changed to CALLs to XERMSG. (THJ)
|
|
* 920501 Reformatted the REFERENCES section. (WRB)
|
|
* 960510 Translated to C and features added. (GWG)
|
|
*/
|
|
|
|
/* Returns status. 0 = OK. */
|
|
int dnsq(
|
|
void *fdata, /* Opaque data pointer, passed to called functions */
|
|
int (*fcn)(void *fdata, int n, double *x, double *fvec, int iflag),
|
|
/* Pointer to function we are solving */
|
|
int (*jac)(void *fdata, int n, double *x, double *fvec, double **fjac),
|
|
/* Optional function to compute jacobian, NULL if not used */
|
|
double **sjac, /* Optional initial jacobian matrix/last jacobian matrix. NULL if not used.*/
|
|
int startsjac, /* Set to non-zero to use sjac as the initial jacobian */
|
|
int n, /* Number of functions and variables */
|
|
double x[], /* Initial solution estimate, RETURNs final solution */
|
|
double fvec[], /* Array that will be RETURNed with thefunction values at the solution */
|
|
double dtol, /* Desired delta tollerance of the solution */
|
|
double atol, /* Desired tollerance of the root (stops on dtol or tol) */
|
|
int maxfev, /* Set excessive Number of Function Evaluations */
|
|
int ml, /* number of subdiagonals within the band of the Jacobian matrix. */
|
|
int mu, /* number of superdiagonals within the band of the Jacobian matrix. */
|
|
double epsfcn, /* determines suitable step for forward-difference approximation */
|
|
double diag[], /* Optional scaling factors, use NULL for internal scaling */
|
|
double factor, /* Determines the initial step bound */
|
|
double maxstep, /* Determines the maximum subsequent step bound (0.0 for none) */
|
|
/* maxstep is NOT WORKING !!! ??? */
|
|
int nprint, /* Turn on debugging printouts from func() every nprint itterations */
|
|
int *nfev, /* RETURNs the number of calls to fcn() */
|
|
int *njev /* RETURNs the number of calls to jac() */
|
|
) {
|
|
int info = 0; /* Return status - invalid argument */
|
|
int smode = 0; /* Scaling mode, 1 = internal */
|
|
|
|
/* Internal working arrays */
|
|
double *fjac = NULL; /* n by n array which contains the orthogonal matrix Q */
|
|
/* produced by the QR factorization of the final approximate Jacobian. */
|
|
int ldfjac = n; /* stride of 2d array */
|
|
double **jjac = NULL; /* NR style pointers to fjac */
|
|
|
|
double *r = NULL; /* Array of length (n*(n+1))/2 which contains the upper */
|
|
/* triangular matrix produced by the QR factorization of the */
|
|
/* final approximate Jacobian, stored rowwise. */
|
|
double *qtf = NULL; /* Array of length n which contains the vector (q transpose)*fvec. */
|
|
|
|
double *wa1 = NULL; /* Four working arrays length n */
|
|
double *wa2 = NULL;
|
|
double *wa3 = NULL;
|
|
double *wa4 = NULL;
|
|
|
|
int iwa[1]; /* Pivot swap array (only one element used) */
|
|
|
|
/* Local variables */
|
|
abool jeval;
|
|
int iter;
|
|
int i, j, k, l, iflag;
|
|
int qrflag; /* Set when a valid Q is in fjac[], and R is in r[] */
|
|
int ncsuc;
|
|
int nslow1, nslow2, ncfail;
|
|
double temp;
|
|
double delta = 0.0;
|
|
double ratio, fnorm, pnorm;
|
|
double xnorm = 0.0;
|
|
double fnorm1;
|
|
double actred, prered;
|
|
double sum;
|
|
|
|
/* Allocate out working arrays */
|
|
if (diag == NULL) { /* Internal scaling */
|
|
smode = 1;
|
|
diag = dvector(0,n-1);
|
|
}
|
|
fjac = dvector(0,(n * n)-1);
|
|
jjac = convert_dmatrix(fjac,0,n-1,0,ldfjac-1);
|
|
r = dvector(0,((n * (n+1))/2)-1);
|
|
qtf = dvector(0,n-1);
|
|
wa1 = dvector(0,n-1);
|
|
wa2 = dvector(0,n-1);
|
|
wa3 = dvector(0,n-1);
|
|
wa4 = dvector(0,n-1);
|
|
|
|
qrflag = 0;
|
|
iflag = 0;
|
|
*nfev = 0;
|
|
*njev = 0;
|
|
|
|
/* Check the input parameters for errors. */
|
|
if (n <= 0 || dtol < 0.0 || maxfev <= 0
|
|
|| ml < 0 || mu < 0 || factor <= 0.0 || maxstep < 0.0
|
|
|| (sjac == NULL && startsjac != 0)) {
|
|
goto func_exit;
|
|
}
|
|
if (!smode) { /* Check the scaling array we were given */
|
|
for (j = 0; j < n; ++j) {
|
|
if (diag[j] <= 0.0) {
|
|
goto func_exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Evaluate the function at the starting point */
|
|
/* and calculate its norm. */
|
|
*nfev = 1;
|
|
if ((iflag = (*fcn)(fdata, n, &x[0], &fvec[0], 1)) < 0)
|
|
goto func_exit;
|
|
fnorm = denorm(n, &fvec[0]);
|
|
|
|
/* Initialize iteration counter and monitors. */
|
|
|
|
iter = 1;
|
|
ncsuc = 0;
|
|
ncfail = 0;
|
|
nslow1 = 0;
|
|
nslow2 = 0;
|
|
|
|
/* Beginning of the outer loop. */
|
|
for (;;) {
|
|
jeval = TRUE;
|
|
|
|
/* initialize the jacobian matrix. */
|
|
if (startsjac) { /* User provided array */
|
|
for (j = 0; j < n; j++) {
|
|
for (i = 0; i < n; i++)
|
|
fjac[j * ldfjac + i] = sjac[j][i];
|
|
}
|
|
} else if (jac == NULL) { /* Code approximates the jacobian */
|
|
int ti;
|
|
iflag = dfdjc1(fdata, fcn, n, &x[0], &fvec[0], &fjac[0], ldfjac,
|
|
ml, mu, epsfcn, &wa1[0], &wa2[0]);
|
|
ti = ml + mu + 1;
|
|
*nfev += min(ti,n);
|
|
} else { /* User supplies jacobian function */
|
|
iflag = (*jac)(fdata, n, &x[0], &fvec[0], jjac);
|
|
++(*njev);
|
|
}
|
|
#ifdef DEBUG
|
|
printf("DNSQ: Jacobian initialized\n");
|
|
#endif
|
|
|
|
if (iflag < 0)
|
|
goto func_exit;
|
|
|
|
/* Compute the qr factorization of the jacobian. */
|
|
dqrfac(n, n, &fjac[0], ldfjac, FALSE, iwa, &wa1[0], &wa2[0], &wa3[0]);
|
|
|
|
/* On the first iteration and if internal scaling mode set, scale */
|
|
/* according to the norms of the columns of the initial jacobian. */
|
|
/* (wa2[] will contain norms) */
|
|
/* Do this on subsequent itterations too, if a maxstep is set. */
|
|
if (iter == 1 || maxstep > 0.0) {
|
|
if (smode) {
|
|
for (j = 0; j < n; ++j) {
|
|
diag[j] = wa2[j];
|
|
if (wa2[j] == 0.0) {
|
|
diag[j] = 1.0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* On the first iteration, calculate the norm of the scaled */
|
|
/* x[], and initialize the step bound delta. */
|
|
for (j = 0; j < n; ++j)
|
|
wa3[j] = diag[j] * x[j];
|
|
|
|
xnorm = denorm(n, &wa3[0]);
|
|
if (iter == 1) {
|
|
delta = factor * xnorm;
|
|
if (delta == 0.0)
|
|
delta = factor;
|
|
#ifdef DEBUG
|
|
printf("Initial Delta = %f\n",delta);
|
|
#endif /* DEBUG */
|
|
} else {
|
|
delta = maxstep * xnorm;
|
|
if (delta == 0.0)
|
|
delta = maxstep;
|
|
#ifdef DEBUG
|
|
printf("Subsequent Delta = %f\n",delta);
|
|
#endif /* DEBUG */
|
|
}
|
|
}
|
|
|
|
/* Form (q transpose)*fvec and store in qtf. */
|
|
for (i = 0; i < n; ++i)
|
|
qtf[i] = fvec[i];
|
|
|
|
for (j = 0; j < n; ++j) {
|
|
if (fjac[j + j * ldfjac] != 0.0) {
|
|
sum = 0.0;
|
|
for (i = j; i < n; ++i)
|
|
sum += fjac[i + j * ldfjac] * qtf[i];
|
|
temp = -sum / fjac[j + j * ldfjac];
|
|
|
|
for (i = j; i < n; ++i)
|
|
qtf[i] += fjac[i + j * ldfjac] * temp;
|
|
}
|
|
}
|
|
|
|
/* Copy the triangular factor of the qr factorization into r. */
|
|
for (j = 0; j < n; ++j) {
|
|
l = j;
|
|
if (j >= 1) {
|
|
for (i = 0; i < j; ++i) {
|
|
r[l] = fjac[i + j * ldfjac];
|
|
l += (n-1) - i;
|
|
}
|
|
}
|
|
r[l] = wa1[j];
|
|
}
|
|
|
|
/* Accumulate the orthogonal factor Q in fjac. */
|
|
dqform(n, n, &fjac[0], ldfjac, &wa1[0]);
|
|
|
|
qrflag = 1;
|
|
|
|
/* Rescale if necessary. */
|
|
if (smode) {
|
|
for (j = 0; j < n; ++j) {
|
|
diag[j] = max(diag[j],wa2[j]);
|
|
}
|
|
}
|
|
|
|
/* Beginning of the inner loop. */
|
|
for (;;) {
|
|
/* If requested, call fcn to enable printing of iterates. */
|
|
if (nprint > 0) {
|
|
if ((iter - 1) % nprint == 0)
|
|
if ((iflag = (*fcn)(fdata, n, &x[0], &fvec[0], 0)) < 0)
|
|
goto func_exit;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
/* If the user supplied an array, and there is a valid Q in */
|
|
/* fjac[], and R is in r[], recover the most recent Jacobian */
|
|
/* matrix by multiplying Q by R */
|
|
if (qrflag && sjac) {
|
|
for (i = 0; i < n; ++i) {
|
|
for (j = 0; j < n; ++j) {
|
|
double temp = 0.0;
|
|
l = j;
|
|
for (k = 0; k <= j; ++k) {
|
|
temp += fjac[k * ldfjac + i] * r[l];
|
|
l += (n-1-k);
|
|
}
|
|
sjac[j][i] = temp;
|
|
}
|
|
}
|
|
printf("Current Jacobian = \n");
|
|
for (j = 0; j < n; ++j) {
|
|
for (i = 0; i < n; ++i) {
|
|
printf("%f ",sjac[j][i]);
|
|
}
|
|
printf("\n");
|
|
}
|
|
}
|
|
#endif /* DEBUG */
|
|
|
|
/* Determine the direction p. */
|
|
ddoglg(n, &r[0], &diag[0], &qtf[0], delta, &wa1[0], &wa2[0], &wa3[0]);
|
|
|
|
/* Store the direction p and x + p. calculate the norm of p. */
|
|
/* (wa1[] is X[] output array from ddoglg()) */
|
|
for (j = 0; j < n; ++j) {
|
|
wa1[j] = -wa1[j];
|
|
wa2[j] = x[j] + wa1[j];
|
|
wa3[j] = diag[j] * wa1[j];
|
|
}
|
|
pnorm = denorm(n, &wa3[0]);
|
|
|
|
/* On the first iteration, adjust the initial step bound. */
|
|
/* Do this on subsequent itterations too, if maxstep is set. */
|
|
if (iter == 1 || maxstep > 0.0) {
|
|
delta = min(delta,pnorm);
|
|
#ifdef DEBUG
|
|
if (iter == 1)
|
|
printf("First itter Delta = %f\n",delta);
|
|
else
|
|
printf("Subsequent itter Delta = %f\n",delta);
|
|
#endif /* DEBUG */
|
|
}
|
|
|
|
/* Evaluate the function at x + p and calculate its norm. */
|
|
++(*nfev);
|
|
if ((iflag = (*fcn)(fdata, n, &wa2[0], &wa4[0], 1)) < 0)
|
|
goto func_exit;
|
|
fnorm1 = denorm(n, &wa4[0]);
|
|
|
|
/* Compute the scaled actual reduction. */
|
|
actred = -1.0; /* Assume norm is made worse */
|
|
if (fnorm1 < fnorm) { /* There was a reduction in the norm */
|
|
double td;
|
|
td = fnorm1 / fnorm;
|
|
actred = 1.0 - td * td;
|
|
}
|
|
|
|
/* Compute the scaled predicted reduction. */
|
|
l = 0;
|
|
for (i = 0; i < n; ++i) {
|
|
sum = 0.0;
|
|
for (j = i; j < n; ++j) {
|
|
sum += r[l] * wa1[j];
|
|
++l;
|
|
}
|
|
wa3[i] = qtf[i] + sum;
|
|
}
|
|
|
|
temp = denorm(n, &wa3[0]);
|
|
prered = 0.0;
|
|
if (temp < fnorm) {
|
|
double td;
|
|
td = temp / fnorm;
|
|
prered = 1.0 - td * td;
|
|
}
|
|
|
|
/* Compute the ratio of the actual to the predicted reduction. */
|
|
ratio = 0.0; /* Assume no improvement */
|
|
if (prered > 0.0)
|
|
ratio = actred / prered;
|
|
#ifdef DEBUG
|
|
printf("DNSQ: actual/predicted ratio = %f\n",ratio);
|
|
#endif /* DEBUG */
|
|
|
|
/* Update the step bound. */
|
|
if (ratio < 0.1) {
|
|
ncsuc = 0;
|
|
++ncfail; /* Forces jacobian recalc when ncfail == 2 */
|
|
delta = 0.5 * delta;
|
|
#ifdef DEBUG
|
|
printf("ratio < 0.1 bad, Delta = %f, ncfail = %d\n",delta,ncfail);
|
|
#endif /* DEBUG */
|
|
} else {
|
|
ncfail = 0; /* Pospone jacobian recalc */
|
|
++ncsuc;
|
|
if (ratio >= 0.5 || ncsuc > 1) {
|
|
delta = max(delta, pnorm / 0.5);
|
|
#ifdef DEBUG
|
|
printf("ratio > 0.1 good, Delta = %f, ncsuc = %d\n",delta,ncsuc);
|
|
#endif /* DEBUG */
|
|
}
|
|
if (fabs(ratio - 1.0) <= 0.1) {
|
|
delta = 2.0 * pnorm;
|
|
#ifdef DEBUG
|
|
printf("abs(ratio -1.0) <= 0.1 Delta = %f\n",delta);
|
|
#endif /* DEBUG */
|
|
}
|
|
}
|
|
|
|
/* Test for progressing iteration. */
|
|
if (ratio > 0.0001) {
|
|
#ifdef DEBUG
|
|
printf("Successful itter\n");
|
|
#endif /* DEBUG */
|
|
/* Successful iteration. update x, fvec, and their norms. */
|
|
for (j = 0; j < n; ++j) {
|
|
x[j] = wa2[j];
|
|
wa2[j] = diag[j] * x[j];
|
|
fvec[j] = wa4[j];
|
|
}
|
|
xnorm = denorm(n, &wa2[0]);
|
|
fnorm = fnorm1;
|
|
++iter;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
printf("DNSQ: actual = %f\n",actred);
|
|
#endif /* DEBUG */
|
|
/* Determine the progress of the iteration. */
|
|
++nslow1;
|
|
if (fabs(actred) >= 0.001)
|
|
nslow1 = 0;
|
|
if (jeval)
|
|
++nslow2;
|
|
if (fabs(actred) >= 0.1)
|
|
nslow2 = 0;
|
|
|
|
/* Test for convergence. */
|
|
if (delta <= dtol * xnorm || fnorm == 0.0) {
|
|
#ifdef DEBUG
|
|
printf("DNSQ: delta %f <= dtol * xnorm %f || fnorm == %f\n",delta,dtol * xnorm,fnorm);
|
|
#endif /* DEBUG */
|
|
info = 1;
|
|
goto func_exit;
|
|
}
|
|
/* Test for root meeting tolerance (GWG) */
|
|
for (j = 0; j < n; ++j) {
|
|
if (fabs(fvec[j]) > atol)
|
|
break;
|
|
}
|
|
if (j >= n) { /* All were below tollerance */
|
|
#ifdef DEBUG
|
|
printf("DNSQ: fvecs are all <= atol %f\n",atol);
|
|
#endif /* DEBUG */
|
|
info = 1;
|
|
goto func_exit;
|
|
}
|
|
|
|
/* Tests for termination and stringent tolerances. */
|
|
if (*nfev >= maxfev)
|
|
info = 2;
|
|
if (0.1 * max(0.1 * delta, pnorm) <= M_DIVER * xnorm)
|
|
info = 3;
|
|
if (nslow2 == 5)
|
|
info = 4;
|
|
if (nslow1 == 10)
|
|
info = 5;
|
|
if (info != 0)
|
|
goto func_exit;
|
|
|
|
/* Criterion for recalculating jacobian */
|
|
if (ncfail == 2) {
|
|
break; /* Break out of inner loop */
|
|
}
|
|
|
|
/* Calculate the rank one modification to the jacobian */
|
|
/* and update qtf if necessary. */
|
|
for (j = 0; j < n; ++j) {
|
|
sum = 0.0;
|
|
for (i = 0; i < n; ++i) {
|
|
sum += fjac[i + j * ldfjac] * wa4[i];
|
|
}
|
|
wa2[j] = (sum - wa3[j]) / pnorm;
|
|
wa1[j] = diag[j] * (diag[j] * wa1[j] / pnorm);
|
|
if (ratio >= 1e-4) {
|
|
qtf[j] = sum;
|
|
}
|
|
}
|
|
|
|
/* Compute the qr factorization of the updated jacobian. */
|
|
d1updt(n, n, &r[0], &wa1[0], &wa2[0], &wa3[0]);
|
|
d1mpyq(n, n, &fjac[0], ldfjac, &wa2[0], &wa3[0]);
|
|
d1mpyq(1, n, &qtf[0], 1, &wa2[0], &wa3[0]);
|
|
|
|
jeval = FALSE;
|
|
} /* End of the inner loop. */
|
|
} /* End of the outer loop. */
|
|
|
|
|
|
/* Termination, either normal or user imposed. */
|
|
func_exit:
|
|
|
|
/* If the user supplied an array, and there is a valid Q in */
|
|
/* fjac[], and R is in r[], recover the most recent Jacobian */
|
|
/* matrix by multiplying Q by R */
|
|
if (qrflag && sjac) {
|
|
for (i = 0; i < n; ++i) {
|
|
for (j = 0; j < n; ++j) {
|
|
double temp = 0.0;
|
|
l = j;
|
|
for (k = 0; k <= j; ++k) {
|
|
temp += fjac[k * ldfjac + i] * r[l];
|
|
l += (n-1-k);
|
|
}
|
|
sjac[j][i] = temp;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Free our working arrays */
|
|
if (smode)
|
|
free_dvector(diag,0,n-1);
|
|
free_dvector(fjac,0,(n * n)-1);
|
|
free_convert_dmatrix(jjac,0,n-1,0,ldfjac-1);
|
|
free_dvector(r,0,((n * (n+1))/2)-1);
|
|
free_dvector(qtf,0,n-1);
|
|
free_dvector(wa1,0,n-1);
|
|
free_dvector(wa2,0,n-1);
|
|
free_dvector(wa3,0,n-1);
|
|
free_dvector(wa4,0,n-1);
|
|
|
|
|
|
if (iflag < 0)
|
|
info = iflag;
|
|
if (nprint > 0)
|
|
(*fcn)(fdata, n, &x[0], &fvec[0], 0);
|
|
#ifdef DEBUG
|
|
if (info < 0)
|
|
printf("dnsq: Execution terminated because user set iflag negative\n");
|
|
if (info == 0)
|
|
printf("dnsq: Invalid input parameter\n");
|
|
if (info == 2)
|
|
printf("dnsq: Too many function evaluations\n");
|
|
if (info == 3)
|
|
printf("dnsq: dtol too small. no further improvement possible\n");
|
|
if (info > 4)
|
|
printf("dnsq: Iteration not making good progress\n");
|
|
#endif /* DEBUG */
|
|
return info;
|
|
} /* dnsq */
|
|
|
|
/***************************************************************/
|
|
/***************************************************************/
|
|
|
|
/*
|
|
* Given an M by N matrix A, this subroutine computes A*Q where
|
|
* Q is the product of 2*(N - 1) transformations
|
|
*
|
|
* GV(N-1)*...*GV(1)*GW(1)*...*GW(N-1)
|
|
*
|
|
* and GV(I), GW(I) are Givens rotations in the (I,N) plane which
|
|
* eliminate elements in the I-th and N-th planes, respectively.
|
|
* Q itself is not given, rather the information to recover the
|
|
* GV, GW rotations is supplied.
|
|
*
|
|
*/
|
|
|
|
static int d1mpyq(
|
|
int m, /* Number of rows of A */
|
|
int n, /* Number of columns of A */
|
|
double *a, /* M by N array */
|
|
int lda, /* stride for a[][] */
|
|
double *v, /* Input array */
|
|
double *w) /* Input array */
|
|
{
|
|
/* Local variables */
|
|
int i, j;
|
|
int nm1 = n - 1;
|
|
double temp;
|
|
double cos_ = 0.0, sin_ = 0.0;
|
|
|
|
/* Apply the first set of givens rotations to a. */
|
|
if (nm1 >= 1) {
|
|
for (j = n-2; j >= 0; --j) {
|
|
if (fabs(v[j]) > 1.0)
|
|
cos_ = 1.0 / v[j];
|
|
if (fabs(v[j]) > 1.0) { /* Computing 2nd power */
|
|
sin_ = sqrt(1.0 - cos_ * cos_);
|
|
}
|
|
if (fabs(v[j]) <= 1.0) {
|
|
sin_ = v[j];
|
|
}
|
|
if (fabs(v[j]) <= 1.0) { /* Computing 2nd power */
|
|
cos_ = sqrt(1.0 - sin_ * sin_);
|
|
}
|
|
for (i = 0; i < m; ++i) {
|
|
temp = cos_ * a[i + j * lda] - sin_ * a[i + nm1 * lda];
|
|
a[i + nm1 * lda] = sin_ * a[i + j * lda] + cos_ * a[i + nm1 * lda];
|
|
a[i + j * lda] = temp;
|
|
}
|
|
}
|
|
|
|
/* Apply the second set of givens rotations to a. */
|
|
for (j = 0; j < nm1; ++j) {
|
|
if (fabs(w[j]) > 1.0)
|
|
cos_ = 1.0 / w[j];
|
|
if (fabs(w[j]) > 1.0) { /* Computing 2nd power */
|
|
sin_ = sqrt(1.0 - cos_ * cos_);
|
|
}
|
|
if (fabs(w[j]) <= 1.0)
|
|
sin_ = w[j];
|
|
if (fabs(w[j]) <= 1.0) { /* Computing 2nd power */
|
|
cos_ = sqrt(1.0 - sin_ * sin_);
|
|
}
|
|
for (i = 0; i < m; ++i) {
|
|
temp = cos_ * a[i + j * lda] + sin_ * a[i + nm1 * lda];
|
|
a[i + nm1 * lda] = -sin_ * a[i + j * lda] + cos_ * a[i + nm1 * lda];
|
|
a[i + j * lda] = temp;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/***************************************************************/
|
|
/***************************************************************/
|
|
|
|
/*
|
|
* Given an M by N lower trapezoidal matrix S, an M-vector U,
|
|
* and an N-vector V, the problem is to determine an
|
|
* orthogonal matrix Q such that
|
|
*
|
|
* t
|
|
* (S + U*V )*Q
|
|
*
|
|
* is again lower trapezoidal.
|
|
*
|
|
* This subroutine determines Q as the product of 2*(N - 1)
|
|
* transformations
|
|
*
|
|
* GV(N-1)*...*GV(1)*GW(1)*...*GW(N-1)
|
|
*
|
|
* where GV(I), GW(I) are Givens rotations in the (I,N) plane
|
|
* which eliminate elements in the I-th and N-th planes,
|
|
* respectively. Q itself is not accumulated, rather the
|
|
* information to recover the GV, GW rotations is returned.
|
|
*
|
|
*/
|
|
|
|
static int d1updt(
|
|
int m, /* Number of rows of S */
|
|
int n, /* Number of columns of S */
|
|
double *s, /* Array of length (n*(2*m-n+1))/2 containing the lower trapezoid matrix */
|
|
double *u, /* U vector lenghth m */
|
|
double *v, /* V vector length n */
|
|
double *w) /* Output array W length m */
|
|
{
|
|
int i, j, l;
|
|
int jj;
|
|
int nm1 = n - 1;
|
|
int nmj;
|
|
double temp;
|
|
double giant, cotan;
|
|
double tan_;
|
|
double cos_, sin_, tau;
|
|
|
|
/* Giant is the largest magnitude. */
|
|
giant = M_LARGE;
|
|
|
|
/* Initialize the diagonal element pointer. */
|
|
jj = n * ((m << 1) - n + 1) / 2 - (m - n) - 1;
|
|
|
|
/* Move the nontrivial part of the last column of s into w. */
|
|
l = jj;
|
|
for (i = nm1; i < m; ++i) {
|
|
w[i] = s[l];
|
|
++l;
|
|
}
|
|
|
|
/* Rotate the vector v into a multiple of the n-th unit vector */
|
|
/* in such a way that a spike is introduced into w. */
|
|
if (nm1 >= 1) {
|
|
for (nmj = 1; nmj <= nm1; ++nmj) {
|
|
j = n - nmj - 1;
|
|
jj -= m - j;
|
|
w[j] = 0.0;
|
|
if (v[j] == 0.0)
|
|
continue;
|
|
|
|
/* Determine a givens rotation which eliminates the */
|
|
/* j-th element of v. */
|
|
if (fabs(v[nm1]) < fabs(v[j])) {
|
|
cotan = v[nm1] / v[j];
|
|
sin_ = 0.5 / sqrt(0.25 + 0.25 * (cotan * cotan));
|
|
cos_ = sin_ * cotan;
|
|
tau = 1.0;
|
|
if (fabs(cos_) * giant > 1.0) {
|
|
tau = 1.0 / cos_;
|
|
}
|
|
} else {
|
|
tan_ = v[j] / v[nm1];
|
|
cos_ = 0.5 / sqrt(0.25 + 0.25 * (tan_ * tan_));
|
|
sin_ = cos_ * tan_;
|
|
tau = sin_;
|
|
}
|
|
|
|
/* Apply the transformation to v and store the information */
|
|
/* necessary to recover the givens rotation. */
|
|
v[nm1] = sin_ * v[j] + cos_ * v[nm1];
|
|
v[j] = tau;
|
|
|
|
/* Apply the transformation to s and extend the spike in w. */
|
|
l = jj;
|
|
for (i = j; i < m; ++i) {
|
|
temp = cos_ * s[l] - sin_ * w[i];
|
|
w[i] = sin_ * s[l] + cos_ * w[i];
|
|
s[l] = temp;
|
|
++l;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Add the spike from the rank 1 update to w. */
|
|
for (i = 0; i < m; ++i)
|
|
w[i] += v[nm1] * u[i];
|
|
|
|
/* Eliminate the spike. */
|
|
if (nm1 >= 1) {
|
|
for (j = 0; j < nm1; ++j) {
|
|
if (w[j] != 0.0) {
|
|
/* Determine a givens rotation which eliminates the */
|
|
/* j-th element of the spike. */
|
|
if (fabs(s[jj]) < fabs(w[j])) {
|
|
cotan = s[jj] / w[j];
|
|
sin_ = 0.5 / sqrt(0.25 + 0.25 * (cotan * cotan));
|
|
cos_ = sin_ * cotan;
|
|
tau = 1.0;
|
|
if (fabs(cos_) * giant > 1.0) {
|
|
tau = 1.0 / cos_;
|
|
}
|
|
} else {
|
|
tan_ = w[j] / s[jj];
|
|
cos_ = 0.5 / sqrt(0.25 + 0.25 * (tan_ * tan_));
|
|
sin_ = cos_ * tan_;
|
|
tau = sin_;
|
|
}
|
|
|
|
/* Apply the transformation to s and reduce the spike in w. */
|
|
l = jj;
|
|
for (i = j; i < m; ++i) {
|
|
temp = cos_ * s[l] + sin_ * w[i];
|
|
w[i] = -sin_ * s[l] + cos_ * w[i];
|
|
s[l] = temp;
|
|
++l;
|
|
}
|
|
|
|
/* Store the information necessary to recover the givens rotation. */
|
|
w[j] = tau;
|
|
}
|
|
jj += m - j;
|
|
}
|
|
}
|
|
|
|
/* Move w back into the last column of the output s. */
|
|
l = jj;
|
|
for (i = nm1; i < m; ++i) {
|
|
s[l] = w[i];
|
|
++l;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/***************************************************************/
|
|
/***************************************************************/
|
|
|
|
/*
|
|
* Given an M by N matrix A, an N by N nonsingular diagonal
|
|
* matrix D, an M-vector B, and a positive number DELTA, the
|
|
* problem is to determine the convex combination X of the
|
|
* Gauss-Newton and scaled gradient directions that minimizes
|
|
* (A*X - B) in the least squares sense, subject to the
|
|
* restriction that the Euclidean norm of D*X be at most DELTA.
|
|
*
|
|
* This subroutine completes the solution of the problem
|
|
* if it is provided with the necessary information from the
|
|
* QR factorization of A. That is, if A = Q*R, where Q has
|
|
* orthogonal columns and R is an upper triangular matrix,
|
|
* then DDOGLG expects the full upper triangle of R and
|
|
* the first N components of (Q transpose)*B.
|
|
*
|
|
*/
|
|
|
|
static int ddoglg(
|
|
int n, /* Order of r[] */
|
|
double r[], /* Array of length (n*(n+!))/2 containing upper triangular matrix */
|
|
double diag[], /* Array of length n containing the diagonal elements of the matrix d[] */
|
|
double qtb[], /* Array of length n containing first n elements of vector (Q transpose)*B */
|
|
double delta, /* Upper bound on the Euclidean norm of D*X */
|
|
double x[], /* output array of length N containing the desired direction */
|
|
double wa1[], /* Working arrays length n */
|
|
double wa2[])
|
|
{
|
|
int i, j, k, l;
|
|
int jj;
|
|
int jp1;
|
|
int nm1 = n-1;
|
|
double temp;
|
|
double alpha, gnorm, qnorm;
|
|
double epsmch;
|
|
double sgnorm;
|
|
double sum;
|
|
|
|
/* Epsmch is the machine precision. */
|
|
epsmch = M_DIVER;
|
|
|
|
/* First, calculate the gauss-newton direction. */
|
|
jj = n * (n + 1) / 2;
|
|
for (k = 0; k < n; ++k) {
|
|
j = nm1 - k;
|
|
jp1 = j + 1;
|
|
jj -= (k+1);
|
|
l = jj + 1;
|
|
sum = 0.0;
|
|
if (n >= (jp1+1)) {
|
|
for (i = jp1; i < n; ++i) {
|
|
sum += r[l] * x[i];
|
|
++l;
|
|
}
|
|
}
|
|
|
|
temp = r[jj];
|
|
if (temp == 0.0) {
|
|
l = j;
|
|
for (i = 0; i <= j; ++i) { /* Computing MAX */
|
|
double dt;
|
|
dt = fabs(r[l]);
|
|
temp = max(temp,dt);
|
|
l += nm1 - i;
|
|
}
|
|
temp = epsmch * temp;
|
|
if (temp == 0.0) {
|
|
temp = epsmch;
|
|
}
|
|
}
|
|
x[j] = (qtb[j] - sum) / temp;
|
|
}
|
|
|
|
|
|
/* Test whether the gauss-newton direction is acceptable. */
|
|
for (j = 0; j < n; ++j) {
|
|
wa1[j] = 0.0;
|
|
wa2[j] = diag[j] * x[j];
|
|
}
|
|
qnorm = denorm(n, &wa2[0]);
|
|
if (qnorm <= delta) {
|
|
return 0; /* Done - use this direction */
|
|
}
|
|
|
|
/* The gauss-newton direction is not acceptable. */
|
|
/* Next, calculate the scaled gradient direction. */
|
|
l = 0;
|
|
for (j = 0; j < n; ++j) {
|
|
temp = qtb[j];
|
|
for (i = j; i < n; ++i) {
|
|
wa1[i] += r[l] * temp;
|
|
++l;
|
|
}
|
|
wa1[j] /= diag[j];
|
|
}
|
|
|
|
/* Calculate the norm of the scaled gradient and test for */
|
|
/* The special case in which the scaled gradient is zero. */
|
|
gnorm = denorm(n, &wa1[0]);
|
|
sgnorm = 0.0;
|
|
alpha = delta / qnorm;
|
|
if (gnorm != 0.0) {
|
|
/* Calculate the point along the scaled gradient */
|
|
/* at which the quadratic is minimized. */
|
|
for (j = 0; j < n; ++j)
|
|
wa1[j] = wa1[j] / gnorm / diag[j];
|
|
l = 0;
|
|
for (j = 0; j < n; ++j) {
|
|
sum = 0.0;
|
|
for (i = j; i < n; ++i) {
|
|
sum += r[l] * wa1[i];
|
|
++l;
|
|
}
|
|
wa2[j] = sum;
|
|
}
|
|
temp = denorm(n, &wa2[0]);
|
|
sgnorm = gnorm / temp / temp;
|
|
|
|
/* Test whether the scaled gradient direction is acceptable. */
|
|
alpha = 0.0;
|
|
if (sgnorm < delta) {
|
|
double d0,d1,d2,d3,d4,
|
|
/* The scaled gradient direction is not acceptable. */
|
|
/* Finally, calculate the point along the dogleg */
|
|
/* at which the quadratic is minimized. */
|
|
bnorm = denorm(n, &qtb[0]);
|
|
d0 = bnorm / gnorm * (bnorm / qnorm) * (sgnorm / delta);
|
|
d1 = sgnorm / delta;
|
|
d2 = d0 - delta / qnorm;
|
|
d3 = delta / qnorm;
|
|
d4 = sgnorm / delta;
|
|
d0 = d0 - delta / qnorm * (d1 * d1)
|
|
+ sqrt(d2 * d2 + (1.0 - d3 * d3) * (1.0 - d4 * d4));
|
|
d1 = sgnorm / delta;
|
|
alpha = delta / qnorm * (1.0 - d1 * d1) / d0;
|
|
}
|
|
}
|
|
|
|
/* Form appropriate convex combination of the gauss-newton */
|
|
/* direction and the scaled gradient direction. */
|
|
temp = (1.0 - alpha) * min(sgnorm,delta);
|
|
for (j = 0; j < n; ++j)
|
|
x[j] = temp * wa1[j] + alpha * x[j];
|
|
|
|
return 0;
|
|
} /* ddoglg */
|
|
|
|
|
|
/***************************************************************/
|
|
/***************************************************************/
|
|
|
|
/*
|
|
* Given an N-vector X, this function calculates the
|
|
* Euclidean norm of X.
|
|
*
|
|
* The Euclidean norm is computed by accumulating the sum of
|
|
* squares in three different sums. The sums of squares for the
|
|
* small and large components are scaled so that no overflows
|
|
* occur. Non-destructive underflows are permitted. Underflows
|
|
* and overflows do not occur in the computation of the unscaled
|
|
* sum of squares for the intermediate components.
|
|
* The definitions of small, intermediate and large components
|
|
* depend on two constants, RDWARF and RGIANT. The main
|
|
* restrictions on these constants are that RDWARF**2 not
|
|
* underflow and RGIANT**2 not overflow. The constants
|
|
* given here are suitable for every known computer.
|
|
*
|
|
*/
|
|
|
|
static double denorm(
|
|
int n, /* Size of x[] */
|
|
double x[]) /* Input vector */
|
|
{
|
|
if (n < 8) { /* Make it simple and fast */
|
|
double ss = 0.0;
|
|
switch (n) {
|
|
case 8:
|
|
ss += x[7] * x[7];
|
|
case 7:
|
|
ss += x[6] * x[6];
|
|
case 6:
|
|
ss += x[5] * x[5];
|
|
case 5:
|
|
ss += x[4] * x[4];
|
|
case 4:
|
|
ss += x[3] * x[3];
|
|
case 3:
|
|
ss += x[2] * x[2];
|
|
case 2:
|
|
ss += x[1] * x[1];
|
|
case 1:
|
|
ss += x[0] * x[0];
|
|
}
|
|
return sqrt(ss);
|
|
} else {
|
|
/* Initialized data */
|
|
static double rdwarf = 3.834e-20;
|
|
static double rgiant = 1.304e19;
|
|
|
|
/* Local variables */
|
|
static double xabs, x1max, x3max;
|
|
static int i;
|
|
static double s1, s2, s3, agiant, floatn;
|
|
double ret_val, td;
|
|
|
|
s1 = 0.0; /* Large component */
|
|
s2 = 0.0; /* Intermedate component */
|
|
s3 = 0.0; /* Small component */
|
|
x1max = 0.0;
|
|
x3max = 0.0;
|
|
floatn = (double) (n + 1);
|
|
agiant = rgiant / floatn;
|
|
for (i = 0; i < n; i++) {
|
|
xabs = (td = x[i], fabs(td));
|
|
|
|
/* Sum for intermediate components. */
|
|
if (xabs > rdwarf && xabs < agiant) {
|
|
td = xabs; /* Computing 2nd power */
|
|
s2 += td * td;
|
|
|
|
/* Sum for small components. */
|
|
} else if (xabs <= rdwarf) {
|
|
if (xabs <= x3max) {
|
|
if (xabs != 0.0) { /* Computing 2nd power */
|
|
td = xabs / x3max;
|
|
s3 += td * td;
|
|
}
|
|
} else { /* Computing 2nd power */
|
|
td = x3max / xabs;
|
|
s3 = 1.0 + s3 * (td * td);
|
|
x3max = xabs;
|
|
}
|
|
|
|
/* Sum for large components. */
|
|
} else {
|
|
if (xabs <= x1max) { /* Computing 2nd power */
|
|
td = xabs / x1max;
|
|
s1 += td * td;
|
|
} else { /* Computing 2nd power */
|
|
td = x1max / xabs;
|
|
s1 = 1.0 + s1 * (td * td);
|
|
x1max = xabs;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Calculation of norm. */
|
|
if (s1 != 0.0) { /* Large is present */
|
|
ret_val = x1max * sqrt(s1 + s2 / x1max / x1max);
|
|
} else { /* Medium and small are present */
|
|
if (s2 == 0.0) {
|
|
ret_val = x3max * sqrt(s3); /* Small only */
|
|
} else {
|
|
if (s2 >= x3max) { /* Medium larger than small */
|
|
ret_val = sqrt(s2 * (1.0 + x3max / s2 * (x3max * s3)));
|
|
} else { /* Small large than medium */
|
|
ret_val = sqrt(x3max * (s2 / x3max + x3max * s3));
|
|
}
|
|
}
|
|
}
|
|
return ret_val;
|
|
}
|
|
}
|
|
|
|
/***************************************************************/
|
|
/***************************************************************/
|
|
|
|
/*
|
|
* This subroutine computes a forward-difference approximation
|
|
* to the N by N Jacobian matrix associated with a specified
|
|
* problem of N functions in N variables. If the Jacobian has
|
|
* a banded form, then function evaluations are saved by only
|
|
* approximating the nonzero terms.
|
|
*
|
|
*/
|
|
|
|
static int dfdjc1( /* Return < 0 if fcn() aborts */
|
|
void *fdata, /* Opaque data pointer to pass to fcn() */
|
|
int (*fcn)(void *fdata, int n, double *x, double *fvec, int iflag),
|
|
/* Pointer to function we are solving */
|
|
int n, /* Number of functions and variables */
|
|
double x[], /* Input array size n */
|
|
double fvec[], /* array of length n which must contain the functions evaluated at x[] */
|
|
double fjac[], /* output n by n array containing approximation to the Jacobian matrix at x[] */
|
|
int ldfjac, /* stride of fjac[] */
|
|
int ml, /* Number of subdiagonals within the band of the Jacobian matrix */
|
|
int mu, /* Number of superdiagonals within the band of the Jacobian matrix */
|
|
double epsfcn, /* Step length for the forward-difference approximation */
|
|
double *wa1, /* Working arrays of length n */
|
|
double *wa2)
|
|
{
|
|
/* Local variables */
|
|
int iflag = 0;
|
|
double temp;
|
|
int msum;
|
|
double h;
|
|
int i, j, k;
|
|
double eps;
|
|
int nm1 = n-1;
|
|
|
|
/* M_DIVER is the machine precision. */
|
|
eps = sqrt((max(epsfcn,M_DIVER)));
|
|
msum = ml + mu + 1;
|
|
if (msum >= n) {
|
|
/* Computation of dense approximate jacobian. */
|
|
for (j = 0; j < n; ++j) {
|
|
temp = x[j];
|
|
h = eps * fabs(temp);
|
|
if (h == 0.0)
|
|
h = eps;
|
|
x[j] = temp + h;
|
|
if ((iflag = (*fcn)(fdata,n, &x[0], &wa1[0], 1)) < 0)
|
|
break;
|
|
x[j] = temp;
|
|
for (i = 0; i < n; ++i)
|
|
fjac[i + j * ldfjac] = (wa1[i] - fvec[i]) / h;
|
|
}
|
|
} else {
|
|
/* Computation of banded approximate jacobian. */
|
|
for (k = 0; k < msum; ++k) {
|
|
for (j = k; msum < 0 ? j >= nm1 : j <= nm1; j += msum) {
|
|
wa2[j] = x[j];
|
|
h = eps * fabs(wa2[j]);
|
|
if (h == 0.0)
|
|
h = eps;
|
|
x[j] = wa2[j] + h;
|
|
}
|
|
if ((iflag = (*fcn)(fdata, n, &x[0], &wa1[0], 1)) < 0)
|
|
break;
|
|
for (j = k; msum < 0 ? j >= nm1 : j <= nm1; j += msum) {
|
|
x[j] = wa2[j];
|
|
h = eps * fabs(wa2[j]);
|
|
if (h == 0.0)
|
|
h = eps;
|
|
for (i = 0; i < n; ++i) {
|
|
fjac[i + j * ldfjac] = 0.0;
|
|
if (i >= j - mu && i <= j + ml)
|
|
fjac[i + j * ldfjac] = (wa1[i] - fvec[i]) / h;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return iflag;
|
|
} /* dfdjc1_ */
|
|
|
|
/***************************************************************/
|
|
/***************************************************************/
|
|
|
|
/*
|
|
* This subroutine proceeds from the computed QR factorization of
|
|
* an M by N matrix A to accumulate the M by M orthogonal matrix
|
|
* Q from its factored form.
|
|
*
|
|
*/
|
|
|
|
static int dqform(
|
|
int m, /* No of rows of A and the order of Q. */
|
|
int n, /* No of columns of A. */
|
|
double *q, /* m by m array */
|
|
int ldq, /* stride of q[][] */
|
|
double *wa) /* Working aray length m */
|
|
{
|
|
int i, j, k, l, minmn;
|
|
double sum;
|
|
|
|
/* Zero out upper triangle of q in the first min(m,n) columns. */
|
|
minmn = min(m,n);
|
|
if (minmn >= 2) {
|
|
for (j = 1; j < minmn; ++j) {
|
|
for (i = 0; i < j; ++i)
|
|
q[i + j * ldq] = 0.0;
|
|
}
|
|
}
|
|
|
|
/* Initialize remaining columns to those of the identity matrix. */
|
|
if (m > n) {
|
|
for (j = n; j < m; ++j) {
|
|
for (i = 0; i < m; ++i) {
|
|
q[i + j * ldq] = 0.0;
|
|
}
|
|
q[j + j * ldq] = 1.0;
|
|
}
|
|
}
|
|
|
|
/* Accumulate q from its factored form. */
|
|
for (l = 0; l < minmn; ++l) {
|
|
k = minmn - l - 1;
|
|
for (i = k; i < m; ++i) {
|
|
wa[i] = q[i + k * ldq];
|
|
q[i + k * ldq] = 0.0;
|
|
}
|
|
q[k + k * ldq] = 1.0;
|
|
if (wa[k] != 0.0) {
|
|
for (j = k; j < m; ++j) {
|
|
double temp;
|
|
sum = 0.0;
|
|
for (i = k; i < m; ++i)
|
|
sum += q[i + j * ldq] * wa[i];
|
|
temp = sum / wa[k];
|
|
for (i = k; i < m; ++i)
|
|
q[i + j * ldq] -= temp * wa[i];
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
} /* dqform_ */
|
|
|
|
/***************************************************************/
|
|
/***************************************************************/
|
|
|
|
/*
|
|
* This subroutine uses Householder transformations with column
|
|
* pivoting (optional) to compute a QR factorization of the
|
|
* M by N matrix A. That is, DQRFAC determines an orthogonal
|
|
* matrix Q, a permutation matrix P, and an upper trapezoidal
|
|
* matrix R with diagonal elements of nonincreasing magnitude,
|
|
* such that A*P = Q*R. The Householder transformation for
|
|
* column K, K = 1,2,...,MIN(M,N), is of the form
|
|
*
|
|
* T
|
|
* I - (1/U(K))*U*U
|
|
*
|
|
* where U has zeros in the first K-1 positions. The form of
|
|
* this transformation and the method of pivoting first
|
|
* appeared in the corresponding LINPACK subroutine.
|
|
*
|
|
*/
|
|
|
|
static int dqrfac(
|
|
int m, /* Number of rows of a[] */
|
|
int n, /* Number of columns of a[] */
|
|
double *a, /* m by n array */
|
|
int lda, /* stride of a[][] */
|
|
abool pivot, /* TRUE to enforce column pivoting */
|
|
int *ipvt, /* Pivot output array, size n */
|
|
double *sigma, /* Output diagonal elements of R, length n */
|
|
double *acnorm, /* Output norms of A, length n */
|
|
double *wa) /* Working array size n */
|
|
{
|
|
/* Local variables */
|
|
int kmax;
|
|
int i, j, k, minmn;
|
|
double ajnorm;
|
|
int jp1;
|
|
double sum;
|
|
|
|
/* Compute the initial column norms and initialize several arrays. */
|
|
for (j = 0; j < n; ++j) {
|
|
acnorm[j] = denorm(m, &a[j * lda]);
|
|
sigma[j] = acnorm[j];
|
|
wa[j] = sigma[j];
|
|
if (pivot)
|
|
ipvt[j] = j;
|
|
}
|
|
|
|
/* Reduce a to r with householder transformations. */
|
|
minmn = min(m,n);
|
|
for (j = 0; j < minmn; ++j) {
|
|
if (pivot) {
|
|
/* Bring the column of largest norm into the pivot position. */
|
|
kmax = j;
|
|
for (k = j; k < n; ++k) {
|
|
if (sigma[k] > sigma[kmax]) {
|
|
kmax = k;
|
|
}
|
|
}
|
|
if (kmax != j) {
|
|
for (i = 0; i < m; ++i) {
|
|
double temp;
|
|
temp = a[i + j * lda];
|
|
a[i + j * lda] = a[i + kmax * lda];
|
|
a[i + kmax * lda] = temp;
|
|
}
|
|
sigma[kmax] = sigma[j];
|
|
wa[kmax] = wa[j];
|
|
k = ipvt[j];
|
|
ipvt[j] = ipvt[kmax];
|
|
ipvt[kmax] = k;
|
|
}
|
|
}
|
|
|
|
/* Compute the householder transformation to reduce the */
|
|
/* j-th column of a to a multiple of the j-th unit vector. */
|
|
ajnorm = denorm(m - j, &a[j + j * lda]);
|
|
if (ajnorm != 0.0) {
|
|
if (a[j + j * lda] < 0.0)
|
|
ajnorm = -ajnorm;
|
|
for (i = j; i < m; ++i)
|
|
a[i + j * lda] /= ajnorm;
|
|
a[j + j * lda] += 1.0;
|
|
|
|
/* Apply the transformation to the remaining columns */
|
|
/* and update the norms. */
|
|
jp1 = j + 1;
|
|
if (n > jp1) {
|
|
for (k = jp1; k < n; ++k) {
|
|
double temp;
|
|
sum = 0.0;
|
|
for (i = j; i < m; ++i)
|
|
sum += a[i + j * lda] * a[i + k * lda];
|
|
temp = sum / a[j + j * lda];
|
|
for (i = j; i < m; ++i)
|
|
a[i + k * lda] -= temp * a[i + j * lda];
|
|
if (pivot && sigma[k] != 0.0) {
|
|
temp = a[j + k * lda] / sigma[k];
|
|
temp = 1.0 - temp * temp;
|
|
sigma[k] *= sqrt((max(0.0,temp)));
|
|
temp = sigma[k] / wa[k];
|
|
if (0.05 * (temp * temp) <= M_DIVER) {
|
|
sigma[k] = denorm(m - jp1, &a[jp1 + k * lda]);
|
|
wa[k] = sigma[k];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
sigma[j] = -ajnorm;
|
|
}
|
|
return 0;
|
|
} /* dqrfac_ */
|
|
|
|
/***************************************************************/
|
|
/***************************************************************/
|
|
|