diff --git a/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/HoltWinters.c b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/HoltWinters.c
new file mode 100644
index 0000000000000000000000000000000000000000..6241fbfa08fca6b04d527a9497b4d286f2e1294b
--- /dev/null
+++ b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/HoltWinters.c
@@ -0,0 +1,99 @@
+/*  R : A Computer Language for Statistical Data Analysis
+ *
+ *  Copyright (C) 2003-7  The R Core Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, a copy is available at
+ *  https://www.R-project.org/Licenses/.
+ */
+
+/* Originally contributed by David Meyer */
+
+#include <stdlib.h>
+#include <string.h>  // memcpy
+
+#include <R.h>
+#include "ts.h"
+
+void HoltWinters (double *x,
+		  int    *xl,
+		  double *alpha,
+		  double *beta,
+		  double *gamma,
+		  int    *start_time,
+		  int    *seasonal,
+		  int    *period,
+		  int    *dotrend,
+		  int    *doseasonal,
+
+		  double *a,
+		  double *b,
+		  double *s,
+
+		  /* return values */
+		  double *SSE,
+		  double *level,
+		  double *trend,
+		  double *season
+    )
+
+{
+    double res = 0, xhat = 0, stmp = 0;
+    int i, i0, s0;
+
+    /* copy start values to the beginning of the vectors */
+    level[0] = *a;
+    if (*dotrend == 1) trend[0] = *b;
+    if (*doseasonal == 1) memcpy(season, s, *period * sizeof(double));
+
+    for (i = *start_time - 1; i < *xl; i++) {
+	/* indices for period i */
+	i0 = i - *start_time + 2;
+	s0 = i0 + *period - 1;
+
+	/* forecast *for* period i */
+	xhat = level[i0 - 1] + (*dotrend == 1 ? trend[i0 - 1] : 0);
+	stmp = *doseasonal == 1 ? season[s0 - *period] : (*seasonal != 1);
+	if (*seasonal == 1)
+	    xhat += stmp;
+	else
+	    xhat *= stmp;
+
+	/* Sum of Squared Errors */
+	res   = x[i] - xhat;
+	*SSE += res * res;
+
+	/* estimate of level *in* period i */
+	if (*seasonal == 1)
+	    level[i0] = *alpha       * (x[i] - stmp)
+		      + (1 - *alpha) * (level[i0 - 1] + trend[i0 - 1]);
+	else
+	    level[i0] = *alpha       * (x[i] / stmp)
+		      + (1 - *alpha) * (level[i0 - 1] + trend[i0 - 1]);
+
+	/* estimate of trend *in* period i */
+	if (*dotrend == 1)
+	    trend[i0] = *beta        * (level[i0] - level[i0 - 1])
+		      + (1 - *beta)  * trend[i0 - 1];
+
+	/* estimate of seasonal component *in* period i */
+	if (*doseasonal == 1) {
+	    if (*seasonal == 1)
+		season[s0] = *gamma       * (x[i] - level[i0])
+			   + (1 - *gamma) * stmp;
+	    else
+		season[s0] = *gamma       * (x[i] / level[i0])
+			   + (1 - *gamma) * stmp;
+	}
+    }
+}
diff --git a/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/Srunmed.c b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/Srunmed.c
new file mode 100644
index 0000000000000000000000000000000000000000..0efdfe21df506779470ab6cf7f6019645aad32d5
--- /dev/null
+++ b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/Srunmed.c
@@ -0,0 +1,214 @@
+/*
+ *  R : A Computer Language for Statistical Data Analysis
+ *  Copyright (C) 1995--2002 Martin Maechler <maechler@stat.math.ethz.ch>
+ *  Copyright (C) 2003       The R Foundation
+ *  Copyright (C) 2012-2016  The R Core Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, a copy is available at
+ *  https://www.R-project.org/Licenses/
+ */
+
+#include "modreg.h"
+
+#include "Trunmed.c"
+
+static void Srunmed(double* y, double* smo, R_xlen_t n, int bw,
+		    int end_rule, int debug)
+{
+/*
+ *  Computes "Running Median" smoother with medians of 'band'
+
+ *  Input:
+ *	y(n)	- responses in order of increasing predictor values
+ *	n	- number of observations
+ *	bw	- span of running medians (MUST be ODD !!)
+ *	end_rule -- 0: Keep original data at ends {j; j < b2 | j > n-b2}
+ *		 -- 1: Constant ends = median(y[1],..,y[bw]) "robust"
+ *  Output:
+ *	smo(n)	- smoothed responses
+
+ * NOTE:  The 'end' values are just copied !! this is fast but not too nice !
+ */
+
+/* Local variables */
+    double rmed, rmin, temp, rnew, yout, yi;
+    double rbe, rtb, rse, yin, rts;
+    int imin, ismo, i, j, first, last, band2, kminus, kplus;
+
+
+    double *scrat = (double *) R_alloc(bw, sizeof(double));
+    /*was  malloc( (unsigned) bw * sizeof(double));*/
+
+    if(bw > n)
+	error(_("bandwidth/span of running medians is larger than n"));
+
+/* 1. Compute  'rmed' := Median of the first 'band' values
+   ======================================================== */
+
+    for (int i = 0; i < bw; ++i)
+	scrat[i] = y[i];
+
+    /* find minimal value  rmin = scrat[imin] <= scrat[j] */
+    rmin = scrat[0]; imin = 0;
+    for (int i = 1; i < bw; ++i)
+	if (scrat[i] < rmin) {
+	    rmin = scrat[i]; imin = i;
+	}
+    /* swap scrat[0] <-> scrat[imin] */
+    temp = scrat[0]; scrat[0] = rmin; scrat[imin] = temp;
+    /* sort the rest of of scrat[] by bubble (?) sort -- */
+    for (int i = 2; i < bw; ++i) {
+	if (scrat[i] < scrat[i - 1]) {/* find the proper place for scrat[i] */
+	    temp = scrat[i];
+	    j = i;
+	    do {
+		scrat[j] = scrat[j - 1];
+		--j;
+	    } while (scrat[j - 1] > temp); /* now:  scrat[j-1] <= temp */
+	    scrat[j] = temp;
+	}
+    }
+
+    band2 = bw / 2;
+    rmed = scrat[band2];/* == Median( y[(1:band2)-1] ) */
+    /* "malloc" had  free( (char*) scrat);*/ /*-- release scratch memory --*/
+
+    if(end_rule == 0) { /*-- keep DATA at end values */
+	for (i = 0; i < band2; ++i)
+	    smo[i] = y[i];
+    }
+    else { /* if(end_rule == 1)  copy median to CONSTANT end values */
+	for (i = 0; i < band2; ++i)
+	    smo[i] = rmed;
+    }
+    smo[band2] = rmed;
+    band2++; /* = bw / 2 + 1*/;
+
+    if(debug) REprintf("(bw,b2)= (%d,%d)\n", bw, band2);
+
+/* Big	FOR Loop: RUNNING median, update the median 'rmed'
+   ======================================================= */
+    for (first = 1, last = bw, ismo = band2;
+	 last < n;
+	 ++first, ++last, ++ismo) {
+
+	yin = y[last];
+	yout = y[first - 1];
+
+	if(debug) REprintf(" is=%d, y(in/out)= %10g, %10g", ismo ,yin, yout);
+
+	rnew = rmed; /* New median = old one   in all the simple cases --*/
+
+	if (yin < rmed) {
+	    if (yout >= rmed) {
+		kminus = 0;
+		if (yout > rmed) {/*	--- yin < rmed < yout --- */
+		    if(debug) REprintf(": yin < rmed < yout ");
+		    rnew = yin;/* was -rinf */
+		    for (i = first; i <= last; ++i) {
+			yi = y[i];
+			if (yi < rmed) {
+			    ++kminus;
+			    if (yi > rnew)	rnew = yi;
+			}
+		    }
+		    if (kminus < band2)		rnew = rmed;
+		}
+		else {/*		--- yin < rmed = yout --- */
+		    if(debug) REprintf(": yin < rmed == yout ");
+		    rse = rts = yin;/* was -rinf */
+		    for (i = first; i <= last; ++i) {
+			yi = y[i];
+			if (yi <= rmed) {
+			    if (yi < rmed) {
+				++kminus;
+				if (yi > rts)	rts = yi;
+				if (yi > rse)	rse = yi;
+			    } else		rse = yi;
+
+			}
+		    }
+		    rnew = (kminus == band2) ? rts : rse ;
+		    if(debug) REprintf("k- : %d,", kminus);
+		}
+	    } /* else: both  yin, yout < rmed -- nothing to do .... */
+	}
+	else if (yin != rmed) { /* yin > rmed */
+	    if (yout <= rmed) {
+		kplus = 0;
+		if (yout < rmed) {/* -- yout < rmed < yin --- */
+		    if(debug) REprintf(": yout < rmed < yin ");
+		    rnew = yin; /* was rinf */
+		    for (i = first; i <= last; ++i) {
+			yi = y[i];
+			if (yi > rmed) {
+			    ++kplus;
+			    if (yi < rnew)	rnew = yi;
+			}
+		    }
+		    if (kplus < band2)	rnew = rmed;
+
+		} else { /* -- yout = rmed < yin --- */
+		    if(debug) REprintf(": yout == rmed < yin ");
+		    rbe = rtb = yin; /* was rinf */
+		    for (i = first; i <= last; ++i) {
+			yi = y[i];
+			if (yi >= rmed) {
+			    if (yi > rmed) {
+				++kplus;
+				if (yi < rtb)	rtb = yi;
+				if (yi < rbe)	rbe = yi;
+			    } else		rbe = yi;
+			}
+		    }
+		    rnew = (kplus == band2) ? rtb : rbe;
+		    if(debug) REprintf("k+ : %d,", kplus);
+		}
+	    } /* else: both  yin, yout > rmed --> nothing to do */
+	} /* else: yin == rmed -- nothing to do .... */
+	if(debug) REprintf("=> %12g, %12g\n", rmed, rnew);
+	rmed = rnew;
+	smo[ismo] = rmed;
+    } /*     END FOR ------------ big Loop -------------------- */
+
+    if(end_rule == 0) { /*-- keep DATA at end values */
+	for (i = ismo; i < n; ++i)
+	    smo[i] = y[i];
+    }
+    else { /* if(end_rule == 1)  copy median to CONSTANT end values */
+	for (i = ismo; i < n; ++i)
+	    smo[i] = rmed;
+    }
+} /* Srunmed */
+
+SEXP runmed(SEXP x, SEXP stype, SEXP sk, SEXP end, SEXP print_level)
+{
+    if (TYPEOF(x) != REALSXP) error("numeric 'x' required");
+    R_xlen_t n = XLENGTH(x);
+    int type = asInteger(stype), k = asInteger(sk),
+	iend = asInteger(end), pl = asInteger(print_level);
+    SEXP ans = PROTECT(allocVector(REALSXP, n));
+    if (type == 1) {
+	if (IS_LONG_VEC(x)) 
+	    error("long vectors are not supported for algorithm = \"Turlach\"");
+	int *i1 = (int *) R_alloc(k + 1, sizeof(int)), 
+	    *i2 = (int *) R_alloc(2*k + 1, sizeof(int));
+	double *d1 = (double *) R_alloc(2*k + 1, sizeof(double));
+	Trunmed(n, k, REAL(x), REAL(ans), i1, i2, d1, iend, pl);
+    } else {
+	Srunmed(REAL(x), REAL(ans), n, k, iend, pl > 0);
+    }
+    UNPROTECT(1);
+    return ans;
+}
diff --git a/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/Trunmed.c b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/Trunmed.c
new file mode 100644
index 0000000000000000000000000000000000000000..efa326b2b543b8549b0667040e6eed4e6c3a042e
--- /dev/null
+++ b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/Trunmed.c
@@ -0,0 +1,378 @@
+/* Copyright (C) 1995   Berwin A. Turlach <berwin@alphasun.anu.edu.au>
+ * Copyright (C) 2000-2 Martin Maechler <maechler@stat.math.ethz.ch>
+ * Copyright (C) 2003   The R Foundation
+ * Copyright (C) 2012-2016   The R Core Team
+
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, a copy is available at
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* These routines implement a running median smoother according to the
+ * algorithm described in Haerdle und Steiger (1995).
+ *
+ * A tech-report of that paper is available under
+ * ftp://amadeus.wiwi.hu-berlin.de/pub/papers/sfb/sfb1994/dpsfb940015.ps.Z
+ *
+ * The current implementation does not use any global variables!
+ */
+
+/* Changes for R port by Martin Maechler ((C) above):
+ *
+ *  s/long/int/			R uses int, not long (as S does)
+ *  s/void/static void/		most routines are internal
+ *
+ * Added  print_level  and end_rule  arguments
+ */
+
+/* Variable	name	descri- | Identities from paper
+ * name here	paper	ption   | (1-indexing)
+ * ---------    -----	-----------------------------------
+ * window[]      H      the array containing the double heap
+ * data[]        X      the data (left intact)
+ * ...		 i	1st permuter  H[i[m]]    == X[i + m]
+ * ...		 j	2nd permuter  X[i +j[m]] == H[m]
+ */
+
+#include <math.h>
+
+static void
+swap(int l, int r, double *window, int *outlist, int *nrlist, int print_level)
+{
+    /* swap positions `l' and `r' in window[] and nrlist[]
+     *
+     * ---- Used in R_heapsort() and many other routines
+     */
+    int nl, nr;
+    double tmp;
+
+    if(print_level >= 3) Rprintf("SW(%d,%d) ", l,r);
+    tmp = window[l]; window[l]	    = window[r];  window[r] = tmp;
+    nl	= nrlist[l]; nrlist[l] = (nr= nrlist[r]); nrlist[r] = nl;
+
+    outlist[nl/* = nrlist[r] */] = r;
+    outlist[nr/* = nrlist[l] */] = l;
+}
+
+static void
+siftup(int l, int r, double *window, int *outlist, int *nrlist, int print_level)
+{
+/* Used only in R_heapsort() */
+    int i, j, nrold;
+    double x;
+
+    if(print_level >= 2) Rprintf("siftup(%d,%d) ", l,r);
+    i	  = l;
+    j	  = 2*i;
+    x	  = window[i];
+    nrold = nrlist[i];
+    while (j <= r) {
+	if (j < r)
+	    if (window[j] < window[j+1])
+		j++;
+	if (x >= window[j])
+	    break;
+
+	window[i]	   = window[j];
+	outlist[nrlist[j]] = i;
+	nrlist[i]	   = nrlist[j];
+	i = j;
+	j = 2*i;
+    }
+    window[i]	   = x;
+    outlist[nrold] = i;
+    nrlist[i]	   = nrold;
+}
+
+static void
+R_heapsort(int low, int up, double *window, int *outlist, int *nrlist,
+	 int print_level)
+{
+    int l, u;
+
+    l = (up/2) + 1;
+    u = up;
+    while(l > low) {
+	l--;
+	siftup(l, u, window, outlist, nrlist, print_level);
+    }
+    while(u > low) {
+	swap(l, u, window, outlist, nrlist, print_level);
+	u--;
+	siftup(l, u, window, outlist, nrlist, print_level);
+    }
+}
+
+static void
+inittree(R_xlen_t n, int k, int k2, const double *data, double *window,
+	 int *outlist, int *nrlist, int print_level)
+{
+    int i, k2p1;
+    double big;
+
+    for(i=1; i <= k; i++) { /* use 1-indexing for our three arrays !*/
+	window[i] = data[i-1];
+	nrlist[i] = outlist[i] = i;
+    }
+
+    /* sort the window[] -- sort *only* called here */
+    R_heapsort(1, k, window, outlist, nrlist, print_level);
+
+    big = fabs(window[k]);
+    if (big < fabs(window[1]))
+	big = fabs(window[1]);
+    /* big := max | X[1..k] | */
+    for(i=k; i < n; i++)
+	if (big < fabs(data[i]))
+	    big = fabs(data[i]);
+    /* big == max(|data_i|,  i = 1,..,n) */
+    big = 1 + 2. * big;/* such that -big < data[] < +big (strictly !) */
+
+    for(i=k; i > 0; i--) {
+	window[i+k2] = window[i];
+	nrlist[i+k2] = nrlist[i]-1;
+    }
+
+    for(i=0; i<k; i++)
+	outlist[i]=outlist[i+1]+k2;
+
+    k2p1 = k2+1;
+    for(i=0; i<k2p1; i++) {
+	window[i]	 = -big;
+	window[k+k2p1+i] =  big;
+    }
+} /* inittree*/
+
+static void
+toroot(int outvirt, int k, R_xlen_t nrnew, int outnext,
+       const double *data, double *window, int *outlist, int *nrlist,
+       int print_level)
+{
+    int father;
+
+    if(print_level >= 2) Rprintf("toroot(%d, %d,%d) ", k, (int) nrnew, outnext);
+
+    do {
+	father			  = outvirt/2;
+	window[outvirt+k]	  = window[father+k];
+	outlist[nrlist[father+k]] = outvirt+k;
+	nrlist[outvirt+k]	  = nrlist[father+k];
+	outvirt			  = father;
+    } while (father != 0);
+    window[k]	     = data[nrnew];
+    outlist[outnext] = k;
+    nrlist[k]	     = outnext;
+}
+
+static void
+downtoleave(int outvirt, int k,
+	    double *window, int *outlist, int *nrlist, int print_level)
+{
+    int childl, childr;
+
+    if(print_level >= 2) Rprintf("\n downtoleave(%d, %d)\n   ", outvirt,k);
+    for(;;) {
+	childl = outvirt*2;
+	childr = childl-1;
+	if (window[childl+k] < window[childr+k])
+	    childl = childr;
+	if (window[outvirt+k] >= window[childl+k])
+	    break;
+	/* seg.fault happens here: invalid outvirt/childl ? */
+	swap(outvirt+k, childl+k, window, outlist, nrlist, print_level);
+	outvirt = childl;
+    }
+}
+
+static void
+uptoleave(int outvirt, int k,
+	  double *window, int *outlist, int *nrlist, int print_level)
+{
+    int childl, childr;
+
+    if(print_level >= 2) Rprintf("\n uptoleave(%d, %d)\n   ", outvirt,k);
+    for(;;) {
+	childl = outvirt*2;
+	childr = childl+1;
+	if (window[childl+k] > window[childr+k])
+	    childl = childr;
+	if (window[outvirt+k] <= window[childl+k])
+	    break;
+	swap(outvirt+k, childl+k, window, outlist, nrlist, print_level);
+	outvirt = childl;
+    }
+}
+
+static void
+upperoutupperin(int outvirt, int k,
+		double *window, int *outlist, int *nrlist, int print_level)
+{
+    int father;
+
+    if(print_level >= 2) Rprintf("\nUpperoutUPPERin(%d, %d)\n  ", outvirt,k);
+    uptoleave(outvirt, k, window, outlist, nrlist, print_level);
+    father = outvirt/2;
+    while (window[outvirt+k] < window[father+k]) {
+	swap(outvirt+k, father+k, window, outlist, nrlist, print_level);
+	outvirt = father;
+	father	= outvirt/2;
+    }
+    if(print_level >= 2) Rprintf("\n");
+}
+
+static void
+upperoutdownin(int outvirt, int k, R_xlen_t nrnew, int outnext,
+	       const double *data, double *window, int *outlist, int *nrlist,
+	       int print_level)
+{
+    if(print_level >= 2) Rprintf("\n__upperoutDOWNin(%d, %d)\n  ", outvirt,k);
+    toroot(outvirt, k, nrnew, outnext, data, window, outlist, nrlist, print_level);
+    if(window[k] < window[k-1]) {
+	swap(k, k-1, window, outlist, nrlist, print_level);
+	downtoleave(/*outvirt = */ -1, k, window, outlist, nrlist, print_level);
+    }
+}
+
+static void
+downoutdownin(int outvirt, int k,
+	      double *window, int *outlist, int *nrlist, int print_level)
+{
+    int father;
+
+    if(print_level >= 2) Rprintf("\nDownoutDOWNin(%d, %d)\n  ", outvirt,k);
+    downtoleave(outvirt, k, window, outlist, nrlist, print_level);
+    father = outvirt/2;
+    while (window[outvirt+k] > window[father+k]) {
+	swap(outvirt+k, father+k, window, outlist, nrlist, print_level);
+	outvirt = father;
+	father	= outvirt/2;
+    }
+    if(print_level >= 2) Rprintf("\n");
+}
+
+static void
+downoutupperin(int outvirt, int k, R_xlen_t nrnew, int outnext,
+	       const double *data, double *window, int *outlist, int *nrlist,
+	       int print_level)
+{
+    if(print_level >= 2) Rprintf("\n__downoutUPPERin(%d, %d)\n  ", outvirt,k);
+    toroot(outvirt, k, nrnew, outnext, data, window, outlist, nrlist, print_level);
+    if(window[k] > window[k+1]) {
+	swap(k, k+1, window, outlist, nrlist, print_level);
+	uptoleave(/*outvirt = */ +1, k, window, outlist, nrlist, print_level);
+    }
+}
+
+static void
+wentoutone(int k, double *window, int *outlist, int *nrlist, int print_level)
+{
+    if(print_level >= 2) Rprintf("\nwentOUT_1(%d)\n  ", k);
+    swap(k, k+1, window, outlist, nrlist, print_level);
+    uptoleave(/*outvirt = */ +1, k, window, outlist, nrlist, print_level);
+}
+
+static void
+wentouttwo(int k, double *window, int *outlist, int *nrlist, int print_level)
+{
+    if(print_level >= 2) Rprintf("\nwentOUT_2(%d)\n  ", k);
+    swap(k, k-1, window, outlist, nrlist, print_level);
+    downtoleave(/*outvirt = */ -1, k, window, outlist, nrlist, print_level);
+}
+
+/* For Printing `diagnostics' : */
+#define Rm_PR(_F_,_A_)		for(j = 0; j <= 2*k; j++) Rprintf(_F_, _A_)
+#define RgPRINT_j(A_J)		Rm_PR("%6g", A_J); Rprintf("\n")
+#define RdPRINT_j(A_J)		Rm_PR("%6d", A_J); Rprintf("\n")
+
+#define R_PRINT_4vec()							\
+	Rprintf(" %9s: ","j");        RdPRINT_j(j);			\
+	Rprintf(" %9s: ","window []");RgPRINT_j(window[j]);		\
+	Rprintf(" %9s: "," nrlist[]");RdPRINT_j(nrlist[j]);		\
+	Rprintf(" %9s: ","outlist[]");RdPRINT_j((j <= k2|| j > k+k2)? -9\
+						: outlist[j - k2])
+
+static void
+runmedint(R_xlen_t n, int k, int k2, const double *data, double *median,
+	  double *window, int *outlist, int *nrlist,
+	  int end_rule, int print_level)
+{
+    /* Running Median of `k' ,  k == 2*k2 + 1 *
+     * end_rule == 0: leave values at the end,
+     *          otherwise: "constant" end values
+     */
+    int outnext, out, outvirt;
+
+    if(end_rule)
+	for(int i = 0; i <= k2; median[i++] = window[k]);
+    else {
+	for(int i = 0; i <  k2; median[i] = data[i], i++);
+	median[k2] = window[k];
+    }
+    outnext = 0;
+    for(R_xlen_t i = k2+1; i < n-k2; i++) {/* compute (0-index) median[i] == X*_{i+1} */
+	out  = outlist[outnext];
+	R_xlen_t nrnew = i+k2;
+	window[out] = data[nrnew];
+	outvirt	= out-k;
+	if (out > k)
+	    if(data[nrnew] >= window[k])
+		upperoutupperin(outvirt, k, window, outlist, nrlist, print_level);
+	    else
+		upperoutdownin(outvirt, k, nrnew, outnext,
+			       data, window, outlist, nrlist, print_level);
+	else if(out < k)
+	    if(data[nrnew] < window[k])
+		downoutdownin(outvirt, k, window, outlist, nrlist, print_level);
+	    else
+		downoutupperin(outvirt, k, nrnew, outnext,
+			       data, window, outlist, nrlist, print_level);
+	else if(window[k] > window[k+1])
+	    wentoutone(k, window, outlist, nrlist, print_level);
+	else if(window[k] < window[k-1])
+	    wentouttwo(k, window, outlist, nrlist, print_level);
+	median[i] = window[k];
+	outnext	  = (outnext+1)%k;
+    }
+    if(end_rule)
+	for(R_xlen_t i = n-k2; i < n; median[i++] = window[k]);
+    else
+	for(R_xlen_t i = n-k2; i < n; median[i] = data[i], i++);
+}/* runmedint() */
+
+/* This is the function called from R or S: */
+static void Trunmed(R_xlen_t n,/* = length(data) */
+		    int k,/* is odd <= n */
+		    const double *data,
+		    double *median, /* (n) */
+		    int   *outlist,/* (k+1) */
+		    int   *nrlist,/* (2k+1) */
+		    double *window,/* (2k+1) */
+		    int   end_rule,
+		    int   print_level)
+{
+    int k2 = (k - 1)/2, /* k == *kk == 2 * k2 + 1 */
+	j;
+
+    inittree (n, k, k2, data,
+	      /* initialize these: */
+	      window, (int *)outlist, (int *)nrlist, (int) print_level);
+
+    /* window[], outlist[], and nrlist[] are all 1-based (indices) */
+
+    if(print_level) {
+	Rprintf("After inittree():\n");
+	R_PRINT_4vec();
+    }
+    runmedint(n, k, k2, data, median, window, outlist, nrlist,
+	      end_rule, print_level);
+}
diff --git a/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/ansari.c b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/ansari.c
new file mode 100644
index 0000000000000000000000000000000000000000..7aed745c4056052364eec184462b5f775fb5afed
--- /dev/null
+++ b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/ansari.c
@@ -0,0 +1,157 @@
+/*
+ *  R : A Computer Language for Statistical Data Analysis
+ *  Copyright (C) 1999-2016  The R Core Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, a copy is available at
+ *  https://www.R-project.org/Licenses/
+ *
+ */
+
+/* ansari.c
+   Compute the exact distribution of the Ansari-Bradley test statistic.
+   */
+
+#include <string.h>
+#include <R.h>
+#include <math.h>  // for floor
+#include <Rmath.h>		/* uses choose() */
+#include "stats.h"
+
+static double ***
+w_init(int m, int n)
+{
+    int i;
+    double ***w;
+
+    w = (double ***) R_alloc(m + 1, sizeof(double **));
+    memset(w, '\0', (m+1) * sizeof(double**));
+    for (i = 0; i <= m; i++) {
+	w[i] = (double**) R_alloc(n + 1, sizeof(double *));
+	memset(w[i], '\0', (n+1) * sizeof(double*));
+    }
+    return(w);
+}
+
+
+static double
+cansari(int k, int m, int n, double ***w)
+{
+    int i, l, u;
+
+    l = (m + 1) * (m + 1) / 4;
+    u = l + m * n / 2;
+
+    if ((k < l) || (k > u))
+	return(0);
+
+    if (w[m][n] == 0) {
+	w[m][n] = (double *) R_alloc(u + 1, sizeof(double));
+	memset(w[m][n], '\0', (u + 1) * sizeof(double));
+	for (i = 0; i <= u; i++)
+	    w[m][n][i] = -1;
+    }
+
+    if (w[m][n][k] < 0) {
+	if (m == 0)
+	    w[m][n][k] = (k == 0);
+	else if (n == 0)
+	    w[m][n][k] = (k == l);
+	else
+	    w[m][n][k] = cansari(k, m, n - 1, w)
+		+ cansari(k - (m + n + 1) / 2, m - 1, n, w);
+    }
+
+    return(w[m][n][k]);
+}
+
+
+static void
+pansari(int len, double *Q, double *P, int m, int n)
+{
+    int i, j, l, u;
+    double c, p, q;
+    double ***w;
+
+    w = w_init(m, n);
+    l = (m + 1) * (m + 1) / 4;
+    u = l + m * n / 2;
+    c = choose(m + n, m);
+    for (i = 0; i < len; i++) {
+	q = floor(Q[i] + 1e-7);
+	if (q < l)
+	    P[i] = 0;
+	else if (q > u)
+	    P[i] = 1;
+	else {
+	    p = 0;
+	    for (j = l; j <= q; j++) p += cansari(j, m, n, w);
+	    P[i] = p / c;
+	}
+    }
+}
+
+static void
+qansari(int len, double *P, double *Q, int m, int n)
+{
+    int i, l, u;
+    double c, p, xi;
+    double ***w;
+
+    w = w_init(m, n);
+    l = (m + 1) * (m + 1) / 4;
+    u = l + m * n / 2;
+    c = choose(m + n, m);
+    for (i = 0; i < len; i++) {
+	xi = P[i];
+	if(xi < 0 || xi > 1)
+	    error(_("probabilities outside [0,1] in qansari()"));
+	if(xi == 0)
+	    Q[i] = l;
+	else if(xi == 1)
+	    Q[i] = u;
+	else {
+	    p = 0.;
+	    int q = 0;
+	    for(;;) {
+		p += cansari(q, m, n, w) / c;
+		if (p >= xi) break;
+		q++;
+	    }
+	    Q[i] = q;
+	}
+    }
+}
+
+#include <Rinternals.h>
+SEXP pAnsari(SEXP q, SEXP sm, SEXP sn)
+{
+    int m = asInteger(sm), n = asInteger(sn);
+    q = PROTECT(coerceVector(q, REALSXP));
+    int len = LENGTH(q);
+    SEXP p = PROTECT(allocVector(REALSXP, len));
+    pansari(len, REAL(q), REAL(p), m, n);
+    UNPROTECT(2);
+    return p;
+}
+
+SEXP qAnsari(SEXP p, SEXP sm, SEXP sn)
+{
+    int m = asInteger(sm), n = asInteger(sn);
+    p = PROTECT(coerceVector(p, REALSXP));
+    int len = LENGTH(p);
+    SEXP q = PROTECT(allocVector(REALSXP, len));
+    qansari(len, REAL(p), REAL(q), m, n);
+    UNPROTECT(2);
+    return q;
+}
diff --git a/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/arima.c b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/arima.c
new file mode 100644
index 0000000000000000000000000000000000000000..3d6fae882305ba267e3a04219d36450befef562c
--- /dev/null
+++ b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/arima.c
@@ -0,0 +1,1125 @@
+/*
+ *  R : A Computer Language for Statistical Data Analysis
+ *  Copyright (C) 2002-2016   The R Core Team.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, a copy is available at
+ *  https://www.R-project.org/Licenses/
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h> // for abs
+#include <string.h>
+
+#include <R.h>
+#include "ts.h"
+#include "statsR.h" // for getListElement
+
+#ifndef max
+#define max(a,b) ((a < b)?(b):(a))
+#endif
+#ifndef min
+#define min(a,b) ((a < b)?(a):(b))
+#endif
+
+
+/* 
+  KalmanLike, internal to StructTS:
+  .Call(C_KalmanLike, y, mod$Z, mod$a, mod$P, mod$T, mod$V, mod$h, mod$Pn,
+        nit, FALSE, update)
+  KalmanRun:
+  .Call(C_KalmanLike, y, mod$Z, mod$a, mod$P, mod$T, mod$V, mod$h, mod$Pn,
+        nit, TRUE, update)
+*/
+
+/* y vector length n of observations
+   Z vector length p for observation equation y_t = Za_t +  eps_t
+   a vector length p of initial state
+   P p x p matrix for initial state uncertainty (contemparaneous)
+   T  p x p transition matrix
+   V  p x p = RQR'
+   h = var(eps_t)
+   anew used for a[t|t-1]
+   Pnew used for P[t|t -1]
+   M used for M = P[t|t -1]Z
+
+   op is FALSE for KalmanLike, TRUE for KalmanRun.  
+   The latter computes residuals and states and has 
+   a more elaborate return value.
+
+   Almost no checking here!
+ */
+
+SEXP
+KalmanLike(SEXP sy, SEXP mod, SEXP sUP, SEXP op, SEXP update)
+{
+    int lop = asLogical(op);
+    mod = PROTECT(duplicate(mod));
+
+    SEXP sZ = getListElement(mod, "Z"), sa = getListElement(mod, "a"), 
+	sP = getListElement(mod, "P"), sT = getListElement(mod, "T"), 
+	sV = getListElement(mod, "V"), sh = getListElement(mod, "h"),
+	sPn = getListElement(mod, "Pn");
+
+    if (TYPEOF(sy) != REALSXP || TYPEOF(sZ) != REALSXP ||
+	TYPEOF(sa) != REALSXP || TYPEOF(sP) != REALSXP ||
+	TYPEOF(sPn) != REALSXP ||
+	TYPEOF(sT) != REALSXP || TYPEOF(sV) != REALSXP)
+	error(_("invalid argument type"));
+
+    int n = LENGTH(sy), p = LENGTH(sa);
+    double *y = REAL(sy), *Z = REAL(sZ), *T = REAL(sT), *V = REAL(sV),
+	*P = REAL(sP), *a = REAL(sa), *Pnew = REAL(sPn), h = asReal(sh);
+
+    double *anew = (double *) R_alloc(p, sizeof(double));
+    double *M = (double *) R_alloc(p, sizeof(double));
+    double *mm = (double *) R_alloc(p * p, sizeof(double));
+    // These are only used if(lop), but avoid -Wall trouble
+    SEXP ans = R_NilValue, resid = R_NilValue, states = R_NilValue;
+    if(lop) {
+	PROTECT(ans = allocVector(VECSXP, 3));
+	SET_VECTOR_ELT(ans, 1, resid = allocVector(REALSXP, n));
+	SET_VECTOR_ELT(ans, 2, states = allocMatrix(REALSXP, n, p));
+	SEXP nm = PROTECT(allocVector(STRSXP, 3));
+	SET_STRING_ELT(nm, 0, mkChar("values"));
+	SET_STRING_ELT(nm, 1, mkChar("resid"));
+	SET_STRING_ELT(nm, 2, mkChar("states"));
+	setAttrib(ans, R_NamesSymbol, nm);
+	UNPROTECT(1);
+    }
+
+    double sumlog = 0.0, ssq = 0.0;
+    int nu = 0;
+    for (int l = 0; l < n; l++) {
+	for (int i = 0; i < p; i++) {
+	    double tmp = 0.0;
+	    for (int k = 0; k < p; k++)
+		tmp += T[i + p * k] * a[k];
+	    anew[i] = tmp;
+	}
+	if (l > asInteger(sUP)) {
+	    for (int i = 0; i < p; i++)
+		for (int j = 0; j < p; j++) {
+		    double tmp = 0.0;
+		    for (int k = 0; k < p; k++)
+			tmp += T[i + p * k] * P[k + p * j];
+		    mm[i + p * j] = tmp;
+		}
+	    for (int i = 0; i < p; i++)
+		for (int j = 0; j < p; j++) {
+		    double tmp = V[i + p * j];
+		    for (int k = 0; k < p; k++)
+			tmp += mm[i + p * k] * T[j + p * k];
+		    Pnew[i + p * j] = tmp;
+		}
+	}
+	if (!ISNAN(y[l])) {
+	    nu++;
+	    double *rr = NULL /* -Wall */;
+	    if(lop) rr = REAL(resid);
+	    double resid0 = y[l];
+	    for (int i = 0; i < p; i++)
+		resid0 -= Z[i] * anew[i];
+	    double gain = h;
+	    for (int i = 0; i < p; i++) {
+		double tmp = 0.0;
+		for (int j = 0; j < p; j++)
+		    tmp += Pnew[i + j * p] * Z[j];
+		M[i] = tmp;
+		gain += Z[i] * M[i];
+	    }
+	    ssq += resid0 * resid0 / gain;
+	    if(lop) rr[l] = resid0 / sqrt(gain);
+	    sumlog += log(gain);
+	    for (int i = 0; i < p; i++)
+		a[i] = anew[i] + M[i] * resid0 / gain;
+	    for (int i = 0; i < p; i++)
+		for (int j = 0; j < p; j++)
+		    P[i + j * p] = Pnew[i + j * p] - M[i] * M[j] / gain;
+	} else {
+	    double *rr = NULL /* -Wall */;
+	    if(lop) rr = REAL(resid);
+	    for (int i = 0; i < p; i++)
+		a[i] = anew[i];
+	    for (int i = 0; i < p * p; i++)
+		P[i] = Pnew[i];
+	    if(lop) rr[l] = NA_REAL;
+	}
+	if(lop) {
+	    double *rs = REAL(states);
+	    for (int j = 0; j < p; j++) rs[l + n*j] = a[j];
+	}
+    }
+
+    SEXP res = PROTECT(allocVector(REALSXP, 2));
+    REAL(res)[0] = ssq/nu; REAL(res)[1] = sumlog/nu;
+    if(lop) {
+	SET_VECTOR_ELT(ans, 0, res);
+	if(asLogical(update)) setAttrib(ans, install("mod"), mod);
+	UNPROTECT(3);
+	return ans;
+    } else {
+	if(asLogical(update)) setAttrib(res, install("mod"), mod);
+	UNPROTECT(2);
+	return res;
+    }
+}
+
+SEXP
+KalmanSmooth(SEXP sy, SEXP mod, SEXP sUP)
+{
+    SEXP sZ = getListElement(mod, "Z"), sa = getListElement(mod, "a"), 
+	sP = getListElement(mod, "P"), sT = getListElement(mod, "T"), 
+	sV = getListElement(mod, "V"), sh = getListElement(mod, "h"),
+	sPn = getListElement(mod, "Pn");
+
+    if (TYPEOF(sy) != REALSXP || TYPEOF(sZ) != REALSXP ||
+	TYPEOF(sa) != REALSXP || TYPEOF(sP) != REALSXP ||
+	TYPEOF(sT) != REALSXP || TYPEOF(sV) != REALSXP)
+	error(_("invalid argument type"));
+
+    SEXP ssa, ssP, ssPn, res, states = R_NilValue, sN;
+    int n = LENGTH(sy), p = LENGTH(sa);
+    double *y = REAL(sy), *Z = REAL(sZ), *a, *P,
+	*T = REAL(sT), *V = REAL(sV), h = asReal(sh), *Pnew;
+    double *at, *rt, *Pt, *gains, *resids, *Mt, *L, gn, *Nt;
+    Rboolean var = TRUE;
+
+    PROTECT(ssa = duplicate(sa)); a = REAL(ssa);
+    PROTECT(ssP = duplicate(sP)); P = REAL(ssP);
+    PROTECT(ssPn = duplicate(sPn)); Pnew = REAL(ssPn);
+
+    PROTECT(res = allocVector(VECSXP, 2));
+    SEXP nm = PROTECT(allocVector(STRSXP, 2));
+    SET_STRING_ELT(nm, 0, mkChar("smooth"));
+    SET_STRING_ELT(nm, 1, mkChar("var"));
+    setAttrib(res, R_NamesSymbol, nm);
+    UNPROTECT(1);
+    SET_VECTOR_ELT(res, 0, states = allocMatrix(REALSXP, n, p));
+    at = REAL(states);
+    SET_VECTOR_ELT(res, 1, sN = allocVector(REALSXP, n*p*p));
+    Nt = REAL(sN);
+
+    double *anew, *mm, *M;
+    anew = (double *) R_alloc(p, sizeof(double));
+    M = (double *) R_alloc(p, sizeof(double));
+    mm = (double *) R_alloc(p * p, sizeof(double));
+
+    Pt = (double *) R_alloc(n * p * p, sizeof(double));
+    gains = (double *) R_alloc(n, sizeof(double));
+    resids = (double *) R_alloc(n, sizeof(double));
+    Mt = (double *) R_alloc(n * p, sizeof(double));
+    L = (double *) R_alloc(p * p, sizeof(double));
+
+    for (int l = 0; l < n; l++) {
+	for (int i = 0; i < p; i++) {
+	    double tmp = 0.0;
+	    for (int k = 0; k < p; k++)
+		tmp += T[i + p * k] * a[k];
+	    anew[i] = tmp;
+	}
+	if (l > asInteger(sUP)) {
+	    for (int i = 0; i < p; i++)
+		for (int j = 0; j < p; j++) {
+		    double tmp = 0.0;
+		    for (int k = 0; k < p; k++)
+			tmp += T[i + p * k] * P[k + p * j];
+		    mm[i + p * j] = tmp;
+		}
+	    for (int i = 0; i < p; i++)
+		for (int j = 0; j < p; j++) {
+		    double tmp = V[i + p * j];
+		    for (int k = 0; k < p; k++)
+			tmp += mm[i + p * k] * T[j + p * k];
+		    Pnew[i + p * j] = tmp;
+		}
+	}
+	for (int i = 0; i < p; i++) at[l + n*i] = anew[i];
+	for (int i = 0; i < p*p; i++) Pt[l + n*i] = Pnew[i];
+	if (!ISNAN(y[l])) {
+	    double resid0 = y[l];
+	    for (int i = 0; i < p; i++)
+		resid0 -= Z[i] * anew[i];
+	    double gain = h;
+	    for (int i = 0; i < p; i++) {
+		double tmp = 0.0;
+		for (int j = 0; j < p; j++)
+		    tmp += Pnew[i + j * p] * Z[j];
+		Mt[l + n*i] = M[i] = tmp;
+		gain += Z[i] * M[i];
+	    }
+	    gains[l] = gain;
+	    resids[l] = resid0;
+	    for (int i = 0; i < p; i++)
+		a[i] = anew[i] + M[i] * resid0 / gain;
+	    for (int i = 0; i < p; i++)
+		for (int j = 0; j < p; j++)
+		    P[i + j * p] = Pnew[i + j * p] - M[i] * M[j] / gain;
+	} else {
+	    for (int i = 0; i < p; i++) {
+		a[i] = anew[i];
+		Mt[l + n * i] = 0.0;
+	    }
+	    for (int i = 0; i < p * p; i++)
+		P[i] = Pnew[i];
+	    gains[l] = NA_REAL;
+	    resids[l] = NA_REAL;
+	}
+    }
+
+    /* rt stores r_{t-1} */
+    rt = (double *) R_alloc(n * p, sizeof(double));
+    for (int l = n - 1; l >= 0; l--) {
+	if (!ISNAN(gains[l])) {
+	    gn = 1/gains[l];
+	    for (int i = 0; i < p; i++)
+		rt[l + n * i] = Z[i] * resids[l] * gn;
+	} else {
+	    for (int i = 0; i < p; i++) rt[l + n * i] = 0.0;
+	    gn = 0.0;
+	}
+
+	if (var) {
+	    for (int i = 0; i < p; i++)
+		for (int j = 0; j < p; j++)
+		    Nt[l + n*i + n*p*j] = Z[i] * Z[j] * gn;
+	}
+
+	if (l < n - 1) {
+	    /* compute r_{t-1} */
+	    for (int i = 0; i < p; i++)
+		for (int j = 0; j < p; j++)
+		    mm[i + p * j] = ((i==j) ? 1:0) - Mt[l + n * i] * Z[j] * gn;
+	    for (int i = 0; i < p; i++)
+		for (int j = 0; j < p; j++) {
+		    double tmp = 0.0;
+		    for (int k = 0; k < p; k++)
+			tmp += T[i + p * k] * mm[k + p * j];
+		    L[i + p * j] = tmp;
+		}
+	    for (int i = 0; i < p; i++) {
+		double tmp = 0.0;
+		for (int j = 0; j < p; j++)
+		    tmp += L[j + p * i] * rt[l + 1 + n * j];
+		rt[l + n * i] += tmp;
+	    }
+	    if(var) { /* compute N_{t-1} */
+		for (int i = 0; i < p; i++)
+		    for (int j = 0; j < p; j++) {
+			double tmp = 0.0;
+			for (int k = 0; k < p; k++)
+			    tmp += L[k + p * i] * Nt[l + 1 + n*k + n*p*j];
+			mm[i + p * j] = tmp;
+		    }
+		for (int i = 0; i < p; i++)
+		    for (int j = 0; j < p; j++) {
+			double tmp = 0.0;
+			for (int k = 0; k < p; k++)
+			    tmp += mm[i + p * k] * L[k + p * j];
+			Nt[l + n*i + n*p*j] += tmp;
+		    }
+	    }
+	}
+
+	for (int i = 0; i < p; i++) {
+	    double tmp = 0.0;
+	    for (int j = 0; j < p; j++)
+		tmp += Pt[l + n*i + n*p*j] * rt[l + n * j];
+	    at[l + n*i] += tmp;
+	}
+    }
+    if (var)
+	for (int l = 0; l < n; l++) {
+	    for (int i = 0; i < p; i++)
+		for (int j = 0; j < p; j++) {
+		    double tmp = 0.0;
+		    for (int k = 0; k < p; k++)
+			tmp += Pt[l + n*i + n*p*k] * Nt[l + n*k + n*p*j];
+		    mm[i + p * j] = tmp;
+		}
+	    for (int i = 0; i < p; i++)
+		for (int j = 0; j < p; j++) {
+		    double tmp = Pt[l + n*i + n*p*j];
+		    for (int k = 0; k < p; k++)
+			tmp -= mm[i + p * k] * Pt[l + n*k + n*p*j];
+		    Nt[l + n*i + n*p*j] = tmp;
+		}
+	}
+    UNPROTECT(4);
+    return res;
+}
+
+
+SEXP
+KalmanFore(SEXP nahead, SEXP mod, SEXP update)
+{
+    mod = PROTECT(duplicate(mod));
+    SEXP sZ = getListElement(mod, "Z"), sa = getListElement(mod, "a"), 
+	sP = getListElement(mod, "P"), sT = getListElement(mod, "T"), 
+	sV = getListElement(mod, "V"), sh = getListElement(mod, "h");
+
+    if (TYPEOF(sZ) != REALSXP ||
+	TYPEOF(sa) != REALSXP || TYPEOF(sP) != REALSXP ||
+	TYPEOF(sT) != REALSXP || TYPEOF(sV) != REALSXP)
+	error(_("invalid argument type"));
+
+    int  n = asInteger(nahead), p = LENGTH(sa);
+    double *Z = REAL(sZ), *a = REAL(sa), *P = REAL(sP), *T = REAL(sT),
+	*V = REAL(sV), h = asReal(sh);
+    double *mm, *anew, *Pnew;
+
+    anew = (double *) R_alloc(p, sizeof(double));
+    Pnew = (double *) R_alloc(p * p, sizeof(double));
+    mm = (double *) R_alloc(p * p, sizeof(double));
+    SEXP res, forecasts, se;
+    PROTECT(res = allocVector(VECSXP, 2));
+    SET_VECTOR_ELT(res, 0, forecasts = allocVector(REALSXP, n));
+    SET_VECTOR_ELT(res, 1, se = allocVector(REALSXP, n));
+    {
+	SEXP nm = PROTECT(allocVector(STRSXP, 2));
+	SET_STRING_ELT(nm, 0, mkChar("pred"));
+	SET_STRING_ELT(nm, 1, mkChar("var"));
+	setAttrib(res, R_NamesSymbol, nm);
+	UNPROTECT(1);
+    }
+    for (int l = 0; l < n; l++) {
+	double fc = 0.0;
+	for (int i = 0; i < p; i++) {
+	    double tmp = 0.0;
+	    for (int k = 0; k < p; k++)
+		tmp += T[i + p * k] * a[k];
+	    anew[i] = tmp;
+	    fc += tmp * Z[i];
+	}
+	for (int i = 0; i < p; i++)
+	    a[i] = anew[i];
+	REAL(forecasts)[l] = fc;
+
+	for (int i = 0; i < p; i++)
+	    for (int j = 0; j < p; j++) {
+		double tmp = 0.0;
+		for (int k = 0; k < p; k++)
+		    tmp += T[i + p * k] * P[k + p * j];
+		mm[i + p * j] = tmp;
+	    }
+	for (int i = 0; i < p; i++)
+	    for (int j = 0; j < p; j++) {
+		double tmp = V[i + p * j];
+		for (int k = 0; k < p; k++)
+		    tmp += mm[i + p * k] * T[j + p * k];
+		Pnew[i + p * j] = tmp;
+	    }
+	double tmp = h;
+	for (int i = 0; i < p; i++)
+	    for (int j = 0; j < p; j++) {
+		P[i + j * p] = Pnew[i + j * p];
+		tmp += Z[i] * Z[j] * P[i + j * p];
+	    }
+	REAL(se)[l] = tmp;
+    }
+    if(asLogical(update)) setAttrib(res, install("mod"), mod);
+    UNPROTECT(2);
+    return res;
+}
+
+
+static void partrans(int p, double *raw, double *new)
+{
+    int j, k;
+    double a, work[100];
+
+    if(p > 100) error(_("can only transform 100 pars in arima0"));
+
+    /* Step one: map (-Inf, Inf) to (-1, 1) via tanh
+       The parameters are now the pacf phi_{kk} */
+    for(j = 0; j < p; j++) work[j] = new[j] = tanh(raw[j]);
+    /* Step two: run the Durbin-Levinson recursions to find phi_{j.},
+       j = 2, ..., p and phi_{p.} are the autoregression coefficients */
+    for(j = 1; j < p; j++) {
+	a = new[j];
+	for(k = 0; k < j; k++)
+	    work[k] -= a * new[j - k - 1];
+	for(k = 0; k < j; k++) new[k] = work[k];
+    }
+}
+
+SEXP ARIMA_undoPars(SEXP sin, SEXP sarma)
+{
+    int *arma = INTEGER(sarma), mp = arma[0], mq = arma[1], msp = arma[2],
+	v, n = LENGTH(sin);
+    double *params, *in = REAL(sin);
+    SEXP res = allocVector(REALSXP, n);
+
+    params = REAL(res);
+    for (int i = 0; i < n; i++) params[i] = in[i];
+    if (mp > 0) partrans(mp, in, params);
+    v = mp + mq;
+    if (msp > 0) partrans(msp, in + v, params + v);
+    return res;
+}
+
+
+SEXP ARIMA_transPars(SEXP sin, SEXP sarma, SEXP strans)
+{
+    int *arma = INTEGER(sarma), trans = asLogical(strans);
+    int mp = arma[0], mq = arma[1], msp = arma[2], msq = arma[3],
+	ns = arma[4], i, j, p = mp + ns * msp, q = mq + ns * msq, v;
+    double *in = REAL(sin), *params = REAL(sin), *phi, *theta;
+    SEXP res, sPhi, sTheta;
+
+    PROTECT(res = allocVector(VECSXP, 2));
+    SET_VECTOR_ELT(res, 0, sPhi = allocVector(REALSXP, p));
+    SET_VECTOR_ELT(res, 1, sTheta = allocVector(REALSXP, q));
+    phi = REAL(sPhi);
+    theta = REAL(sTheta);
+    if (trans) {
+	int n = mp + mq + msp + msq;
+
+	params = (double *) R_alloc(n, sizeof(double));
+	for (i = 0; i < n; i++) params[i] = in[i];
+	if (mp > 0) partrans(mp, in, params);
+	v = mp + mq;
+	if (msp > 0) partrans(msp, in + v, params + v);
+    }
+    if (ns > 0) {
+	/* expand out seasonal ARMA models */
+	for (i = 0; i < mp; i++) phi[i] = params[i];
+	for (i = 0; i < mq; i++) theta[i] = params[i + mp];
+	for (i = mp; i < p; i++) phi[i] = 0.0;
+	for (i = mq; i < q; i++) theta[i] = 0.0;
+	for (j = 0; j < msp; j++) {
+	    phi[(j + 1) * ns - 1] += params[j + mp + mq];
+	    for (i = 0; i < mp; i++)
+		phi[(j + 1) * ns + i] -= params[i] * params[j + mp + mq];
+	}
+	for (j = 0; j < msq; j++) {
+	    theta[(j + 1) * ns - 1] += params[j + mp + mq + msp];
+	    for (i = 0; i < mq; i++)
+		theta[(j + 1) * ns + i] += params[i + mp] *
+		    params[j + mp + mq + msp];
+	}
+    } else {
+	for (i = 0; i < mp; i++) phi[i] = params[i];
+	for (i = 0; i < mq; i++) theta[i] = params[i + mp];
+    }
+    UNPROTECT(1);
+    return res;
+}
+
+#if !defined(atanh) && defined(HAVE_DECL_ATANH) && !HAVE_DECL_ATANH
+extern double atanh(double x);
+#endif
+static void invpartrans(int p, double *phi, double *new)
+{
+    int j, k;
+    double a, work[100];
+
+    if(p > 100) error(_("can only transform 100 pars in arima0"));
+
+    for(j = 0; j < p; j++) work[j] = new[j] = phi[j];
+    /* Run the Durbin-Levinson recursions backwards
+       to find the PACF phi_{j.} from the autoregression coefficients */
+    for(j = p - 1; j > 0; j--) {
+	a = new[j];
+	for(k = 0; k < j; k++)
+	    work[k]  = (new[k] + a * new[j - k - 1]) / (1 - a * a);
+	for(k = 0; k < j; k++) new[k] = work[k];
+    }
+    for(j = 0; j < p; j++) new[j] = atanh(new[j]);
+}
+
+SEXP ARIMA_Invtrans(SEXP in, SEXP sarma)
+{
+    int *arma = INTEGER(sarma), mp = arma[0], mq = arma[1], msp = arma[2],
+	i, v, n = LENGTH(in);
+    SEXP y = allocVector(REALSXP, n);
+    double *raw = REAL(in), *new = REAL(y);
+
+    for(i = 0; i < n; i++) new[i] = raw[i];
+    if (mp > 0) invpartrans(mp, raw, new);
+    v = mp + mq;
+    if (msp > 0) invpartrans(msp, raw + v, new + v);
+    return y;
+}
+
+#define eps 1e-3
+SEXP ARIMA_Gradtrans(SEXP in, SEXP sarma)
+{
+    int *arma = INTEGER(sarma), mp = arma[0], mq = arma[1], msp = arma[2],
+	n = LENGTH(in);
+    SEXP y = allocMatrix(REALSXP, n, n);
+    double *raw = REAL(in), *A = REAL(y), w1[100], w2[100], w3[100];
+
+    for (int i = 0; i < n; i++)
+	for (int j = 0; j < n; j++)
+	    A[i + j*n] = (i == j);
+    if(mp > 0) {
+	for (int i = 0; i < mp; i++) w1[i] = raw[i];
+	partrans(mp, w1, w2);
+	for (int i = 0; i < mp; i++) {
+	    w1[i] += eps;
+	    partrans(mp, w1, w3);
+	    for (int j = 0; j < mp; j++) A[i + j*n] = (w3[j] - w2[j])/eps;
+	    w1[i] -= eps;
+	}
+    }
+    if(msp > 0) {
+	int v = mp + mq;
+	for (int i = 0; i < msp; i++) w1[i] = raw[i + v];
+	partrans(msp, w1, w2);
+	for(int i = 0; i < msp; i++) {
+	    w1[i] += eps;
+	    partrans(msp, w1, w3);
+	    for(int j = 0; j < msp; j++)
+		A[i + v + (j+v)*n] = (w3[j] - w2[j])/eps;
+	    w1[i] -= eps;
+	}
+    }
+    return y;
+}
+
+
+SEXP
+ARIMA_Like(SEXP sy, SEXP mod, SEXP sUP, SEXP giveResid)
+{
+    SEXP sPhi = getListElement(mod, "phi"), 
+	sTheta = getListElement(mod, "theta"), 
+	sDelta = getListElement(mod, "Delta"),
+	sa = getListElement(mod, "a"),
+	sP = getListElement(mod, "P"),
+	sPn = getListElement(mod, "Pn");
+
+    if (TYPEOF(sPhi) != REALSXP || TYPEOF(sTheta) != REALSXP ||
+	TYPEOF(sDelta) != REALSXP || TYPEOF(sa) != REALSXP ||
+	TYPEOF(sP) != REALSXP || TYPEOF(sPn) != REALSXP)
+	error(_("invalid argument type"));
+
+    SEXP res, nres, sResid = R_NilValue;
+    int n = LENGTH(sy), rd = LENGTH(sa), p = LENGTH(sPhi),
+	q = LENGTH(sTheta), d = LENGTH(sDelta), r = rd - d;
+    double *y = REAL(sy), *a = REAL(sa), *P = REAL(sP), *Pnew = REAL(sPn);
+    double *phi = REAL(sPhi), *theta = REAL(sTheta), *delta = REAL(sDelta);
+    double sumlog = 0.0, ssq = 0, *anew, *mm = NULL, *M;
+    int nu = 0;
+    Rboolean useResid = asLogical(giveResid);
+    double *rsResid = NULL /* -Wall */;
+
+    anew = (double *) R_alloc(rd, sizeof(double));
+    M = (double *) R_alloc(rd, sizeof(double));
+    if (d > 0) mm = (double *) R_alloc(rd * rd, sizeof(double));
+
+    if (useResid) {
+	PROTECT(sResid = allocVector(REALSXP, n));
+	rsResid = REAL(sResid);
+    }
+
+    for (int l = 0; l < n; l++) {
+	for (int i = 0; i < r; i++) {
+	    double tmp = (i < r - 1) ? a[i + 1] : 0.0;
+	    if (i < p) tmp += phi[i] * a[0];
+	    anew[i] = tmp;
+	}
+	if (d > 0) {
+	    for (int i = r + 1; i < rd; i++) anew[i] = a[i - 1];
+	    double tmp = a[0];
+	    for (int i = 0; i < d; i++) tmp += delta[i] * a[r + i];
+	    anew[r] = tmp;
+	}
+	if (l > asInteger(sUP)) {
+	    if (d == 0) {
+		for (int i = 0; i < r; i++) {
+		    double vi = 0.0;
+		    if (i == 0) vi = 1.0; else if (i - 1 < q) vi = theta[i - 1];
+		    for (int j = 0; j < r; j++) {
+			double tmp = 0.0;
+			if (j == 0) tmp = vi; else if (j - 1 < q) tmp = vi * theta[j - 1];
+			if (i < p && j < p) tmp += phi[i] * phi[j] * P[0];
+			if (i < r - 1 && j < r - 1) tmp += P[i + 1 + r * (j + 1)];
+			if (i < p && j < r - 1) tmp += phi[i] * P[j + 1];
+			if (j < p && i < r - 1) tmp += phi[j] * P[i + 1];
+			Pnew[i + r * j] = tmp;
+		    }
+		}
+	    } else {
+		/* mm = TP */
+		for (int i = 0; i < r; i++)
+		    for (int j = 0; j < rd; j++) {
+			double tmp = 0.0;
+			if (i < p) tmp += phi[i] * P[rd * j];
+			if (i < r - 1) tmp += P[i + 1 + rd * j];
+			mm[i + rd * j] = tmp;
+		    }
+		for (int j = 0; j < rd; j++) {
+		    double tmp = P[rd * j];
+		    for (int k = 0; k < d; k++)
+			tmp += delta[k] * P[r + k + rd * j];
+		    mm[r + rd * j] = tmp;
+		}
+		for (int i = 1; i < d; i++)
+		    for (int j = 0; j < rd; j++)
+			mm[r + i + rd * j] = P[r + i - 1 + rd * j];
+
+		/* Pnew = mmT' */
+		for (int i = 0; i < r; i++)
+		    for (int j = 0; j < rd; j++) {
+			double tmp = 0.0;
+			if (i < p) tmp += phi[i] * mm[j];
+			if (i < r - 1) tmp += mm[rd * (i + 1) + j];
+			Pnew[j + rd * i] = tmp;
+		    }
+		for (int j = 0; j < rd; j++) {
+		    double tmp = mm[j];
+		    for (int k = 0; k < d; k++)
+			tmp += delta[k] * mm[rd * (r + k) + j];
+		    Pnew[rd * r + j] = tmp;
+		}
+		for (int i = 1; i < d; i++)
+		    for (int j = 0; j < rd; j++)
+			Pnew[rd * (r + i) + j] = mm[rd * (r + i - 1) + j];
+		/* Pnew <- Pnew + (1 theta) %o% (1 theta) */
+		for (int i = 0; i <= q; i++) {
+		    double vi = (i == 0) ? 1. : theta[i - 1];
+		    for (int j = 0; j <= q; j++)
+			Pnew[i + rd * j] += vi * ((j == 0) ? 1. : theta[j - 1]);
+		}
+	    }
+	}
+	if (!ISNAN(y[l])) {
+	    double resid = y[l] - anew[0];
+	    for (int i = 0; i < d; i++)
+		resid -= delta[i] * anew[r + i];
+
+	    for (int i = 0; i < rd; i++) {
+		double tmp = Pnew[i];
+		for (int j = 0; j < d; j++)
+		    tmp += Pnew[i + (r + j) * rd] * delta[j];
+		M[i] = tmp;
+	    }
+
+	    double gain = M[0];
+	    for (int j = 0; j < d; j++) gain += delta[j] * M[r + j];
+	    if(gain < 1e4) {
+		nu++;
+		ssq += resid * resid / gain;
+		sumlog += log(gain);
+	    }
+	    if (useResid) rsResid[l] = resid / sqrt(gain);
+	    for (int i = 0; i < rd; i++)
+		a[i] = anew[i] + M[i] * resid / gain;
+	    for (int i = 0; i < rd; i++)
+		for (int j = 0; j < rd; j++)
+		    P[i + j * rd] = Pnew[i + j * rd] - M[i] * M[j] / gain;
+	} else {
+	    for (int i = 0; i < rd; i++) a[i] = anew[i];
+	    for (int i = 0; i < rd * rd; i++) P[i] = Pnew[i];
+	    if (useResid) rsResid[l] = NA_REAL;
+	}
+    }
+
+    if (useResid) {
+	PROTECT(res = allocVector(VECSXP, 3));
+	SET_VECTOR_ELT(res, 0, nres = allocVector(REALSXP, 3));
+	REAL(nres)[0] = ssq;
+	REAL(nres)[1] = sumlog;
+	REAL(nres)[2] = (double) nu;
+	SET_VECTOR_ELT(res, 1, sResid);
+	UNPROTECT(2);
+	return res;
+    } else {
+	nres = allocVector(REALSXP, 3);
+	REAL(nres)[0] = ssq;
+	REAL(nres)[1] = sumlog;
+	REAL(nres)[2] = (double) nu;
+	return nres;
+    }
+}
+
+/* do differencing here */
+/* arma is p, q, sp, sq, ns, d, sd */
+SEXP
+ARIMA_CSS(SEXP sy, SEXP sarma, SEXP sPhi, SEXP sTheta,
+	  SEXP sncond, SEXP giveResid)
+{
+    SEXP res, sResid = R_NilValue;
+    double ssq = 0.0, *y = REAL(sy), tmp;
+    double *phi = REAL(sPhi), *theta = REAL(sTheta), *w, *resid;
+    int n = LENGTH(sy), *arma = INTEGER(sarma), p = LENGTH(sPhi),
+	q = LENGTH(sTheta), ncond = asInteger(sncond);
+    int ns, nu = 0;
+    Rboolean useResid = asLogical(giveResid);
+
+    w = (double *) R_alloc(n, sizeof(double));
+    for (int l = 0; l < n; l++) w[l] = y[l];
+    for (int i = 0; i < arma[5]; i++)
+	for (int l = n - 1; l > 0; l--) w[l] -= w[l - 1];
+    ns = arma[4];
+    for (int i = 0; i < arma[6]; i++)
+	for (int l = n - 1; l >= ns; l--) w[l] -= w[l - ns];
+
+    PROTECT(sResid = allocVector(REALSXP, n));
+    resid = REAL(sResid);
+    if (useResid) for (int l = 0; l < ncond; l++) resid[l] = 0;
+
+    for (int l = ncond; l < n; l++) {
+	tmp = w[l];
+	for (int j = 0; j < p; j++) tmp -= phi[j] * w[l - j - 1];
+	for (int j = 0; j < min(l - ncond, q); j++)
+	    tmp -= theta[j] * resid[l - j - 1];
+	resid[l] = tmp;
+	if (!ISNAN(tmp)) {
+	    nu++;
+	    ssq += tmp * tmp;
+	}
+    }
+    if (useResid) {
+	PROTECT(res = allocVector(VECSXP, 2));
+	SET_VECTOR_ELT(res, 0, ScalarReal(ssq / (double) (nu)));
+	SET_VECTOR_ELT(res, 1, sResid);
+	UNPROTECT(2);
+	return res;
+    } else {
+	UNPROTECT(1);
+	return ScalarReal(ssq / (double) (nu));
+    }
+}
+
+SEXP TSconv(SEXP a, SEXP b)
+{
+    int na, nb, nab;
+    SEXP ab;
+    double *ra, *rb, *rab;
+
+    PROTECT(a = coerceVector(a, REALSXP));
+    PROTECT(b = coerceVector(b, REALSXP));
+    na = LENGTH(a);
+    nb = LENGTH(b);
+    nab = na + nb - 1;
+    PROTECT(ab = allocVector(REALSXP, nab));
+    ra = REAL(a); rb = REAL(b); rab = REAL(ab);
+    for (int i = 0; i < nab; i++) rab[i] = 0.0;
+    for (int i = 0; i < na; i++)
+	for (int j = 0; j < nb; j++)
+	    rab[i + j] += ra[i] * rb[j];
+    UNPROTECT(3);
+    return (ab);
+}
+
+/* based on code from AS154 */
+
+static void
+inclu2(size_t np, double *xnext, double *xrow, double ynext,
+       double *d, double *rbar, double *thetab)
+{
+    double cbar, sbar, di, xi, xk, rbthis, dpi;
+    size_t i, k, ithisr;
+
+/*   This subroutine updates d, rbar, thetab by the inclusion
+     of xnext and ynext. */
+
+    for (i = 0; i < np; i++) xrow[i] = xnext[i];
+
+    for (ithisr = 0, i = 0; i < np; i++) {
+	if (xrow[i] != 0.0) {
+	    xi = xrow[i];
+	    di = d[i];
+	    dpi = di + xi * xi;
+	    d[i] = dpi;
+	    cbar = di / dpi;
+	    sbar = xi / dpi;
+	    for (k = i + 1; k < np; k++) {
+		xk = xrow[k];
+		rbthis = rbar[ithisr];
+		xrow[k] = xk - xi * rbthis;
+		rbar[ithisr++] = cbar * rbthis + sbar * xk;
+	    }
+	    xk = ynext;
+	    ynext = xk - xi * thetab[i];
+	    thetab[i] = cbar * thetab[i] + sbar * xk;
+	    if (di == 0.0) return;
+	} else
+	    ithisr = ithisr + np - i - 1;
+    }
+}
+
+#ifdef DEBUG_Q0bis
+# include <R_ext/Print.h>
+  double chk_V(double v[], char* nm, int jj, int len) { 
+    // len = length(<vector>)  <==> index must be in  {0, len-1}
+    if(jj < 0 || jj >= len)
+	REprintf(" %s[%2d]\n", nm, jj); 
+    return(v[jj]); 
+  }
+#endif
+
+/*
+  Matwey V. Kornilov's implementation of algorithm by
+  Dr. Raphael Rossignol
+  See https://bugs.r-project.org/bugzilla3/show_bug.cgi?id=14682 for details.
+*/
+SEXP getQ0bis(SEXP sPhi, SEXP sTheta, SEXP sTol)
+{
+    SEXP res;
+    int p = LENGTH(sPhi), q = LENGTH(sTheta);
+    double *phi = REAL(sPhi), *theta = REAL(sTheta); // tol = REAL(sTol)[0];
+
+    int i,j, r = max(p, q + 1);
+
+    /* Final result is block product 
+     *   Q0 = A1 SX A1^T + A1 SXZ A2^T + (A1 SXZ A2^T)^T + A2 A2^T ,
+     * where A1 [i,j] = phi[i+j],
+     *       A2 [i,j] = ttheta[i+j],  and SX, SXZ are defined below */
+    PROTECT(res = allocMatrix(REALSXP, r, r));
+    double *P = REAL(res);
+
+    /* Clean P */
+    Memzero(P, r*r);
+
+#ifdef DEBUG_Q0bis
+#define _ttheta(j) chk_V(ttheta, "ttheta", j, q+1)// was  r
+#define _tphi(j)   chk_V(tphi,   "tphi",   j, p+1)
+#define _rrz(j)    chk_V(rrz,    "rrz",    j, q)
+#else
+#define _ttheta(j) ttheta[j]
+#define _tphi(j) tphi[j]
+#define _rrz(j)  rrz [j]
+#endif
+
+    double *ttheta = (double *) R_alloc(q + 1, sizeof(double));
+    /* Init ttheta = c(1, theta) */
+    ttheta[0] = 1.;
+    for (i = 1; i < q + 1; ++i) ttheta[i] = theta[i - 1];
+
+    if( p > 0 ) {
+	int r2 = max(p + q, p + 1);
+	SEXP sgam = PROTECT(allocMatrix(REALSXP, r2, r2)),
+	    sg = PROTECT(allocVector(REALSXP, r2));
+	double *gam = REAL(sgam);
+	double *g = REAL(sg);
+	double *tphi = (double *) R_alloc(p + 1, sizeof(double));
+	/* Init tphi = c(1, -phi) */
+	tphi[0] = 1.;
+	for (i = 1; i < p + 1; ++i) tphi[i] = -phi[i - 1];
+
+    /* Compute the autocovariance function of U, the AR part of X */
+
+    /* Gam := C1 + C2 ; initialize */
+	Memzero(gam, r2*r2);
+
+    /* C1[E] */
+	for (j = 0; j < r2; ++j)
+	    for (i = j; i < r2 && i - j < p + 1; ++i)
+		gam[j*r2 + i] += _tphi(i-j);
+
+    /* C2[E] */
+	for (i = 0; i < r2; ++i)
+	    for (j = 1; j < r2 && i + j < p + 1; ++j)
+		gam[j*r2 + i] += _tphi(i+j);
+
+    /* Initialize g = (1 0 0 .... 0) */
+	g[0] = 1.;
+	for (i = 1; i < r2; ++i)
+	    g[i] = 0.;
+
+    /* rU = solve(Gam, g)  -> solve.default() -> .Internal(La_solve, .,)
+     * --> fiddling with R-objects -> C and then F77_CALL(.) of dgesv, dlange, dgecon
+     * FIXME: call these directly here, possibly even use 'info' instead of error(.)
+     * e.g., in case of exact singularity.
+     */
+	SEXP callS = PROTECT(lang4(install("solve.default"), sgam, sg, sTol)),
+	    su = PROTECT(eval(callS, R_BaseEnv));
+	double *u = REAL(su);
+    /* SX = A SU A^T */
+    /* A[i,j]  = ttheta[j-i] */
+    /* SU[i,j] = u[abs(i-j)] */
+    /* Q0 += ( A1 SX A1^T == A1 A SU A^T A1^T) */
+	// (relying on good compiler optimization here:)
+	for (i = 0; i < r; ++i)
+	    for (j = i; j < r; ++j)
+		for (int k = 0; i + k < p; ++k)
+		    for (int L = k; L - k < q + 1; ++L)
+			for (int m = 0; j + m < p; ++m)
+			    for (int n = m; n - m < q + 1; ++n)
+				P[r*i + j] += phi[i + k] * phi[j + m] *
+				    _ttheta(L - k) * _ttheta(n - m) * u[abs(L - n)];
+	UNPROTECT(4);
+    /* Compute correlation matrix between X and Z */
+    /* forwardsolve(C1, g) */
+    /* C[i,j] = tphi[i-j] */
+    /* g[i] = _ttheta(i) */
+	double *rrz = (double *) R_alloc(q, sizeof(double));
+	if(q > 0) {
+	    for (i = 0; i < q; ++i) {
+		rrz[i] = _ttheta(i);
+		for (j = max(0, i - p); j < i; ++j)
+		    rrz[i] -= _rrz(j) * _tphi(i-j);
+	    }
+	}
+
+    /* Q0 += A1 SXZ A2^T + (A1 SXZ A2^T)^T */
+    /* SXZ[i,j] = rrz[j-i-1], j > 0 */
+	for (i = 0; i < r; ++i)
+	    for (j = i; j < r; ++j) {
+		int k, L;
+		for (k = 0; i + k < p; ++k)
+		    for (L = k+1; j + L < q + 1; ++L)
+			P[r*i + j] += phi[i + k] * _ttheta(j + L) * _rrz(L - k - 1);
+		for (k = 0; j + k < p; ++k)
+		    for (L = k+1; i + L < q + 1; ++L)
+			P[r*i + j] += phi[j + k] * _ttheta(i + L) * _rrz(L - k - 1);
+	    }
+    } // end if(p > 0)
+
+    /* Q0 += A2 A2^T */
+    for (i = 0; i < r; ++i)
+	for (j = i; j < r; ++j)
+	    for (int k = 0; j + k < q + 1; ++k)
+		 P[r*i + j] += _ttheta(i + k) * _ttheta(j + k);
+
+    /* Symmetrize result */
+    for (i = 0; i < r; ++i)
+	for (j = i+1; j < r; ++j)
+	    P[r*j + i] = P[r*i + j];
+
+    UNPROTECT(1);
+    return res;
+}
+
+SEXP getQ0(SEXP sPhi, SEXP sTheta)
+{
+    SEXP res;
+    int  p = LENGTH(sPhi), q = LENGTH(sTheta);
+    double *phi = REAL(sPhi), *theta = REAL(sTheta);
+
+    /* thetab[np], xnext[np], xrow[np].  rbar[rbar] */
+    /* NB: nrbar could overflow */
+    int r = max(p, q + 1);
+    size_t np = r * (r + 1) / 2, nrbar = np * (np - 1) / 2, npr, npr1;
+    size_t indi, indj, indn, i, j, ithisr, ind, ind1, ind2, im, jm;
+
+
+    /* This is the limit using an int index.  We could use
+       size_t and get more on a 64-bit system,
+       but there seems no practical need. */
+    if(r > 350) error(_("maximum supported lag is 350"));
+    double *xnext, *xrow, *rbar, *thetab, *V;
+    xnext = (double *) R_alloc(np, sizeof(double));
+    xrow = (double *) R_alloc(np, sizeof(double));
+    rbar = (double *) R_alloc(nrbar, sizeof(double));
+    thetab = (double *) R_alloc(np, sizeof(double));
+    V = (double *) R_alloc(np, sizeof(double));
+    for (ind = 0, j = 0; j < r; j++) {
+	double vj = 0.0;
+	if (j == 0) vj = 1.0; else if (j - 1 < q) vj = theta[j - 1];
+	for (i = j; i < r; i++) {
+	    double vi = 0.0;
+	    if (i == 0) vi = 1.0; else if (i - 1 < q) vi = theta[i - 1];
+	    V[ind++] = vi * vj;
+	}
+    }
+
+    PROTECT(res = allocMatrix(REALSXP, r, r));
+    double *P = REAL(res);
+
+    if (r == 1) {
+	if (p == 0) P[0] = 1.0; // PR#16419
+	else P[0] = 1.0 / (1.0 - phi[0] * phi[0]);
+	UNPROTECT(1);
+	return res;
+    }
+    if (p > 0) {
+/*      The set of equations s * vec(P0) = vec(v) is solved for
+	vec(P0).  s is generated row by row in the array xnext.  The
+	order of elements in P is changed, so as to bring more leading
+	zeros into the rows of s. */
+
+	for (i = 0; i < nrbar; i++) rbar[i] = 0.0;
+	for (i = 0; i < np; i++) {
+	    P[i] = 0.0;
+	    thetab[i] = 0.0;
+	    xnext[i] = 0.0;
+	}
+	ind = 0;
+	ind1 = -1;
+	npr = np - r;
+	npr1 = npr + 1;
+	indj = npr;
+	ind2 = npr - 1;
+	for (j = 0; j < r; j++) {
+	    double phij = (j < p) ? phi[j] : 0.0;
+	    xnext[indj++] = 0.0;
+	    indi = npr1 + j;
+	    for (i = j; i < r; i++) {
+		double ynext = V[ind++];
+		double phii = (i < p) ? phi[i] : 0.0;
+		if (j != r - 1) {
+		    xnext[indj] = -phii;
+		    if (i != r - 1) {
+			xnext[indi] -= phij;
+			xnext[++ind1] = -1.0;
+		    }
+		}
+		xnext[npr] = -phii * phij;
+		if (++ind2 >= np) ind2 = 0;
+		xnext[ind2] += 1.0;
+		inclu2(np, xnext, xrow, ynext, P, rbar, thetab);
+		xnext[ind2] = 0.0;
+		if (i != r - 1) {
+		    xnext[indi++] = 0.0;
+		    xnext[ind1] = 0.0;
+		}
+	    }
+	}
+
+	ithisr = nrbar - 1;
+	im = np - 1;
+	for (i = 0; i < np; i++) {
+	    double bi = thetab[im];
+	    for (jm = np - 1, j = 0; j < i; j++)
+		bi -= rbar[ithisr--] * P[jm--];
+	    P[im--] = bi;
+	}
+
+/*        now re-order p. */
+
+	ind = npr;
+	for (i = 0; i < r; i++) xnext[i] = P[ind++];
+	ind = np - 1;
+	ind1 = npr - 1;
+	for (i = 0; i < npr; i++) P[ind--] = P[ind1--];
+	for (i = 0; i < r; i++) P[i] = xnext[i];
+    } else {
+
+/* P0 is obtained by backsubstitution for a moving average process. */
+
+	indn = np;
+	ind = np;
+	for (i = 0; i < r; i++)
+	    for (j = 0; j <= i; j++) {
+		--ind;
+		P[ind] = V[ind];
+		if (j != 0) P[ind] += P[--indn];
+	    }
+    }
+    /* now unpack to a full matrix */
+    for (i = r - 1, ind = np; i > 0; i--)
+	for (j = r - 1; j >= i; j--)
+	    P[r * i + j] = P[--ind];
+    for (i = 0; i < r - 1; i++)
+	for (j = i + 1; j < r; j++)
+	    P[i + r * j] = P[j + r * i];
+    UNPROTECT(1);
+    return res;
+}
diff --git a/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/bandwidths.c b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/bandwidths.c
new file mode 100644
index 0000000000000000000000000000000000000000..404c4c7477d6668c58f68440046ae909f5f26b23
--- /dev/null
+++ b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/bandwidths.c
@@ -0,0 +1,171 @@
+/*
+ *  R : A Computer Language for Statistical Data Analysis
+ *  bandwidth.c by W. N. Venables and B. D. Ripley  Copyright (C) 1994-2001
+ *  Copyright (C) 2012-2017  The R Core Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, a copy is available at
+ *  https://www.R-project.org/Licenses/
+ */
+
+#include <stdlib.h> //abs
+#include <math.h>
+#include <Rmath.h> // M_* constants
+#include <Rinternals.h>
+
+// or include "stats.h"
+#ifdef ENABLE_NLS
+#include <libintl.h>
+#define _(String) dgettext ("stats", String)
+#else
+#define _(String) (String)
+#endif
+
+#define DELMAX 1000
+/* Avoid slow and possibly error-producing underflows by cutting off at
+   plus/minus sqrt(DELMAX) std deviations */
+/* Formulae (6.67) and (6.69) of Scott (1992), the latter corrected. */
+
+SEXP bw_ucv(SEXP sn, SEXP sd, SEXP cnt, SEXP sh)
+{
+    double h = asReal(sh), d = asReal(sd), sum = 0.0, term, u;
+    int n = asInteger(sn), nbin = LENGTH(cnt);
+    double *x = REAL(cnt);
+    for (int i = 0; i < nbin; i++) {
+	double delta = i * d / h;
+	delta *= delta;
+	if (delta >= DELMAX) break;
+	term = exp(-delta / 4.) - sqrt(8.0) * exp(-delta / 2.);
+	sum += term * x[i];
+    }
+    u = (0.5 + sum/n) / (n * h * M_SQRT_PI);
+    // = 1 / (2 * n * h * sqrt(PI)) + sum / (n * n * h * sqrt(PI));
+    return ScalarReal(u);
+}
+
+SEXP bw_bcv(SEXP sn, SEXP sd, SEXP cnt, SEXP sh)
+{
+    double h = asReal(sh), d = asReal(sd), sum = 0.0, term, u;
+    int n = asInteger(sn), nbin = LENGTH(cnt);
+    double *x = REAL(cnt);
+
+    sum = 0.0;
+    for (int i = 0; i < nbin; i++) {
+	double delta = i * d / h; delta *= delta;
+	if (delta >= DELMAX) break;
+	term = exp(-delta / 4) * (delta * delta - 12 * delta + 12);
+	sum += term * x[i];
+    }
+    u = (1 + sum/(32.0*n)) / (2.0 * n * h * M_SQRT_PI);
+    // = 1 / (2 * n * h * sqrt(PI)) + sum / (64 * n * n * h * sqrt(PI));
+    return ScalarReal(u);
+}
+
+SEXP bw_phi4(SEXP sn, SEXP sd, SEXP cnt, SEXP sh)
+{
+    double h = asReal(sh), d = asReal(sd), sum = 0.0, term, u;
+    int n = asInteger(sn), nbin = LENGTH(cnt);
+    double *x = REAL(cnt);
+
+    for (int i = 0; i < nbin; i++) {
+	double delta = i * d / h; delta *= delta;
+	if (delta >= DELMAX) break;
+	term = exp(-delta / 2.) * (delta * delta - 6. * delta + 3.);
+	sum += term * x[i];
+    }
+    sum = 2. * sum + n * 3.;	/* add in diagonal */
+    u = sum / ((double)n * (n - 1) * pow(h, 5.0)) * M_1_SQRT_2PI;
+    // = sum / (n * (n - 1) * pow(h, 5.0) * sqrt(2 * PI));
+    return ScalarReal(u);
+}
+
+SEXP bw_phi6(SEXP sn, SEXP sd, SEXP cnt, SEXP sh)
+{
+    double h = asReal(sh), d = asReal(sd), sum = 0.0, term, u;
+    int n = asInteger(sn), nbin = LENGTH(cnt);
+    double *x = REAL(cnt);
+
+    for (int i = 0; i < nbin; i++) {
+	double delta = i * d / h; delta *= delta;
+	if (delta >= DELMAX) break;
+	term = exp(-delta / 2) *
+	    (delta * delta * delta - 15 * delta * delta + 45 * delta - 15);
+	sum += term * x[i];
+    }
+    sum = 2. * sum - 15. * n;	/* add in diagonal */
+    u = sum / ((double)n * (n - 1) * pow(h, 7.0)) * M_1_SQRT_2PI;
+    // = sum / (n * (n - 1) * pow(h, 7.0) * sqrt(2 * PI));
+    return ScalarReal(u);
+}
+
+/*
+   Use double cnt as from R 3.4.0, as counts can exceed INT_MAX for
+   large n (65537 in the worse case but typically not at n = 1 million
+   for a smooth distribution -- and this is by default no longer used
+   for n > 500).
+*/
+
+SEXP bw_den(SEXP nbin, SEXP sx)
+{
+    int nb = asInteger(nbin), n = LENGTH(sx);
+    double xmin, xmax, rang, dd, *x = REAL(sx);
+
+    xmin = R_PosInf; xmax = R_NegInf;
+    for (int i = 0; i < n; i++) {
+	if(!R_FINITE(x[i]))
+	    error(_("non-finite x[%d] in bandwidth calculation"), i+1);
+	if(x[i] < xmin) xmin = x[i];
+	if(x[i] > xmax) xmax = x[i];
+    }
+    rang = (xmax - xmin) * 1.01;
+    dd = rang / nb;
+
+    SEXP ans = PROTECT(allocVector(VECSXP, 2)),
+	sc = SET_VECTOR_ELT(ans, 1, allocVector(REALSXP, nb));
+    SET_VECTOR_ELT(ans, 0, ScalarReal(dd));
+    double *cnt = REAL(sc);
+    for (int i = 0; i < nb; i++) cnt[i] = 0.0;
+
+    for (int i = 1; i < n; i++) {
+	int ii = (int)(x[i] / dd);
+	for (int j = 0; j < i; j++) {
+	    int jj = (int)(x[j] / dd);
+	    cnt[abs(ii - jj)] += 1.0;
+	}
+    }
+
+    UNPROTECT(1);
+    return ans;
+}
+
+/* Input: counts for nb bins */
+SEXP bw_den_binned(SEXP sx)
+{
+    int nb = LENGTH(sx);
+    int *x = INTEGER(sx);
+
+    SEXP ans = PROTECT(allocVector(REALSXP, nb));
+    double *cnt = REAL(ans);
+    for (int ib = 0; ib < nb; ib++) cnt[ib] = 0.0;
+
+    for (int ii = 0; ii < nb; ii++) {
+	int w = x[ii];
+	cnt[0] += w*(w-1.); // don't count distances to self
+	for (int jj = 0; jj < ii; jj++)
+	    cnt[ii - jj] += w * x[jj];
+    }
+    cnt[0] *= 0.5; // counts in the same bin got double-counted
+
+    UNPROTECT(1);
+    return ans;
+}
diff --git a/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/burg.c b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/burg.c
new file mode 100644
index 0000000000000000000000000000000000000000..df4e81423599b1d03c3e82fdf739743267116dc4
--- /dev/null
+++ b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/burg.c
@@ -0,0 +1,82 @@
+/*
+ *  R : A Computer Language for Statistical Data Analysis
+
+ *  Copyright (C) 1999-2016  The R Core Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, a copy is available at
+ *  https://www.R-project.org/Licenses/.
+ */
+
+#include <R.h>
+
+static void
+burg(int n, double*x, int pmax, double *coefs, double *var1, double *var2)
+{
+    double d, phii, *u, *v, *u0, sum;
+
+    u = (double *) R_alloc(n, sizeof(double));
+    v = (double *) R_alloc(n, sizeof(double));
+    u0 = (double *) R_alloc(n, sizeof(double));
+
+    for(int i = 0; i < pmax*pmax; i++) coefs[i] = 0.0;
+    sum = 0.0;
+    for(int t = 0; t < n; t++) {
+	u[t] = v[t] = x[n - 1 - t];
+	sum += x[t] * x[t];
+    }
+    var1[0] = var2[0] = sum/n;
+    for(int p = 1; p <= pmax; p++) { /* do AR(p) */
+	sum = 0.0;
+	d = 0;
+	for(int t = p; t < n; t++) {
+	    sum += v[t]*u[t-1];
+	    d += v[t]*v[t] + u[t-1]*u[t-1];
+	}
+	phii = 2*sum/d;
+	coefs[pmax*(p-1) + (p-1)] = phii;
+	if(p > 1)
+	    for(int j = 1; j < p; j++)
+		coefs[p-1 + pmax*(j-1)] =
+		    coefs[p-2 + pmax*(j-1)] - phii* coefs[p-2 + pmax*(p-j-1)];
+	/* update u and v */
+	for(int t = 0; t < n; t++)
+	    u0[t] = u[t];
+	for(int t = p; t < n; t++) {
+	    u[t] = u0[t-1] - phii * v[t];
+	    v[t] = v[t] - phii * u0[t-1];
+	}
+	var1[p] = var1[p-1] * (1 - phii * phii);
+	d = 0.0;
+	for(int t = p; t < n; t++) d += v[t]*v[t] + u[t]*u[t];
+	var2[p] = d/(2.0*(n-p));
+    }
+}
+
+#include <Rinternals.h>
+
+SEXP Burg(SEXP x, SEXP order)
+{
+    x = PROTECT(coerceVector(x, REALSXP));
+    int n = LENGTH(x), pmax = asInteger(order);
+    SEXP coefs = PROTECT(allocVector(REALSXP, pmax * pmax)),
+	var1 = PROTECT(allocVector(REALSXP, pmax + 1)),
+	var2 = PROTECT(allocVector(REALSXP, pmax + 1));
+    burg(n, REAL(x), pmax, REAL(coefs), REAL(var1), REAL(var2));
+    SEXP ans = PROTECT(allocVector(VECSXP, 3));
+    SET_VECTOR_ELT(ans, 0, coefs);
+    SET_VECTOR_ELT(ans, 1, var1);
+    SET_VECTOR_ELT(ans, 2, var2);
+    UNPROTECT(5);
+    return ans;
+}
diff --git a/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/d2x2xk.c b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/d2x2xk.c
new file mode 100644
index 0000000000000000000000000000000000000000..0047ee6f35e8819ccddaeec3e5fc0c27312b1092
--- /dev/null
+++ b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/d2x2xk.c
@@ -0,0 +1,65 @@
+/*
+ *  R : A Computer Language for Statistical Data Analysis
+ *  Copyright (C) 2000-2016  The R Core Team.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, a copy is available at
+ *  https://www.R-project.org/Licenses/
+ */
+
+/* for mantelhaen.test */
+
+#include <R.h>
+#include <Rmath.h>
+
+static void
+int_d2x2xk(int K, double *m, double *n, double *t, double *d)
+{
+    int i, j, l, w, y, z;
+    double u, **c;
+
+    c = (double **) R_alloc(K + 1, sizeof(double *));
+    l = y = z = 0;
+    c[0] = (double *) R_alloc(1, sizeof(double));
+    c[0][0] = 1;
+    for(i = 0; i < K; i++) {
+	y = imax2(0,  (int)(*t - *n));
+	z = imin2((int)*m, (int)*t);
+	c[i + 1] = (double *) R_alloc(l + z - y + 1, sizeof(double));
+	for(j = 0; j <= l + z - y; j++) c[i + 1][j] = 0;
+	for(j = 0; j <= z - y; j++) {
+	    u = dhyper(j + y, *m, *n, *t, FALSE);
+	    for(w = 0; w <= l; w++) c[i + 1][w + j] += c[i][w] * u;
+	}
+	l = l + z - y;
+	m++; n++; t++;
+    }
+
+    u = 0;
+    for(j = 0; j <= l; j++) u += c[K][j];
+    for(j = 0; j <= l; j++) d[j] = c[K][j] / u;
+}
+
+#include <Rinternals.h>
+
+SEXP d2x2xk(SEXP sK, SEXP m, SEXP n, SEXP t, SEXP srn)
+{
+    int K = asInteger(sK), rn = asInteger(srn);
+    m = PROTECT(coerceVector(m, REALSXP));
+    n = PROTECT(coerceVector(n, REALSXP));
+    t = PROTECT(coerceVector(t, REALSXP));
+    SEXP ans = PROTECT(allocVector(REALSXP, rn));
+    int_d2x2xk(K, REAL(m), REAL(n), REAL(t), REAL(ans));
+    UNPROTECT(4);
+    return ans;
+}
diff --git a/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/family.c b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/family.c
new file mode 100644
index 0000000000000000000000000000000000000000..ab96566199fc69f9bfcb82df1e74d2691ff108b2
--- /dev/null
+++ b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/family.c
@@ -0,0 +1,155 @@
+/*
+ *  R : A Computer Language for Statistical Data Analysis
+ *  Copyright (C) 2005-2016  The R Core Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, a copy is available at
+ *  https://www.R-project.org/Licenses/
+ *
+ *  Quartz Quartz device module header file
+ *
+ */
+
+#include <Rinternals.h>
+#include <Rconfig.h>
+#include <R_ext/Constants.h>
+#include <float.h>
+#include <math.h>
+#include "stats.h"
+#include "statsR.h"
+
+static const double THRESH = 30.;
+static const double MTHRESH = -30.;
+static const double INVEPS = 1/DOUBLE_EPS;
+
+/**
+ * Evaluate x/(1 - x). An inline function is used so that x is
+ * evaluated once only.
+ *
+ * @param x input in the range (0, 1)
+ *
+ * @return x/(1 - x)
+ */
+static R_INLINE double x_d_omx(double x) {
+    if (x < 0 || x > 1)
+	error(_("Value %g out of range (0, 1)"), x);
+    return x/(1 - x);
+}
+
+/**
+ * Evaluate x/(1 + x). An inline function is used so that x is
+ * evaluated once only. [but inlining is optional!]
+ *
+ * @param x input
+ *
+ * @return x/(1 + x)
+ */
+static R_INLINE double x_d_opx(double x) {return x/(1 + x);}
+
+SEXP logit_link(SEXP mu)
+{
+    int i, n = LENGTH(mu);
+    SEXP ans = PROTECT(shallow_duplicate(mu));
+    double *rans = REAL(ans), *rmu=REAL(mu);
+
+    if (!n || !isReal(mu))
+	error(_("Argument %s must be a nonempty numeric vector"), "mu");
+    for (i = 0; i < n; i++)
+	rans[i] = log(x_d_omx(rmu[i]));
+    UNPROTECT(1);
+    return ans;
+}
+
+SEXP logit_linkinv(SEXP eta)
+{
+    SEXP ans = PROTECT(shallow_duplicate(eta));
+    int i, n = LENGTH(eta);
+    double *rans = REAL(ans), *reta = REAL(eta);
+
+    if (!n || !isReal(eta))
+	error(_("Argument %s must be a nonempty numeric vector"), "eta");
+    for (i = 0; i < n; i++) {
+	double etai = reta[i], tmp;
+	tmp = (etai < MTHRESH) ? DOUBLE_EPS :
+	    ((etai > THRESH) ? INVEPS : exp(etai));
+	rans[i] = x_d_opx(tmp);
+    }
+    UNPROTECT(1);
+    return ans;
+}
+
+SEXP logit_mu_eta(SEXP eta)
+{
+    SEXP ans = PROTECT(shallow_duplicate(eta));
+    int i, n = LENGTH(eta);
+    double *rans = REAL(ans), *reta = REAL(eta);
+
+    if (!n || !isReal(eta))
+	error(_("Argument %s must be a nonempty numeric vector"), "eta");
+    for (i = 0; i < n; i++) {
+	double etai = reta[i];
+	double opexp = 1 + exp(etai);
+
+	rans[i] = (etai > THRESH || etai < MTHRESH) ? DOUBLE_EPS :
+	    exp(etai)/(opexp * opexp);
+    }
+    UNPROTECT(1);
+    return ans;
+}
+
+static R_INLINE
+double y_log_y(double y, double mu)
+{
+    return (y != 0.) ? (y * log(y/mu)) : 0;
+}
+
+SEXP binomial_dev_resids(SEXP y, SEXP mu, SEXP wt)
+{
+    int i, n = LENGTH(y), lmu = LENGTH(mu), lwt = LENGTH(wt), nprot = 1;
+    SEXP ans;
+    double mui, yi, *rmu, *ry, *rwt, *rans;
+
+    if (!isReal(y)) {y = PROTECT(coerceVector(y, REALSXP)); nprot++;}
+    ry = REAL(y);
+    ans = PROTECT(shallow_duplicate(y));
+    rans = REAL(ans);
+    if (!isReal(mu)) {mu = PROTECT(coerceVector(mu, REALSXP)); nprot++;}
+    if (!isReal(wt)) {wt = PROTECT(coerceVector(wt, REALSXP)); nprot++;}
+    rmu = REAL(mu);
+    rwt = REAL(wt);
+    if (lmu != n && lmu != 1)
+	error(_("argument %s must be a numeric vector of length 1 or length %d"),
+	      "mu", n);
+    if (lwt != n && lwt != 1)
+	error(_("argument %s must be a numeric vector of length 1 or length %d"),
+	      "wt", n);
+    /* Written separately to avoid an optimization bug on Solaris cc */
+    if(lmu > 1) {
+	for (i = 0; i < n; i++) {
+	    mui = rmu[i];
+	    yi = ry[i];
+	    rans[i] = 2 * rwt[lwt > 1 ? i : 0] *
+		(y_log_y(yi, mui) + y_log_y(1 - yi, 1 - mui));
+	}
+    } else {
+	mui = rmu[0];
+	for (i = 0; i < n; i++) {
+	    yi = ry[i];
+	    rans[i] = 2 * rwt[lwt > 1 ? i : 0] *
+		(y_log_y(yi, mui) + y_log_y(1 - yi, 1 - mui));
+	}
+    }
+
+    UNPROTECT(nprot);
+    return ans;
+}
diff --git a/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/fexact.c b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/fexact.c
new file mode 100644
index 0000000000000000000000000000000000000000..7d9c64aa43b23104668c0f2c13a6e6620be8c40f
--- /dev/null
+++ b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/fexact.c
@@ -0,0 +1,2077 @@
+/*
+ *  R : A Computer Language for Statistical Data Analysis
+ *  Copyright (C) 1999-2010   The R Core Team.
+ *
+ *  Based on ACM TOMS643 (1993)
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, a copy is available at
+ *  https://www.R-project.org/Licenses/
+ */
+
+/* -*- mode: c; kept-new-versions: 25; kept-old-versions: 20 -*-
+
+   Fisher's exact test for contingency tables -- usage see below
+
+   fexact.f -- translated by f2c (version 19971204).
+   Run through a slightly modified version of MM's f2c-clean.
+   Heavily hand-edited by KH and MM.
+ */
+
+/* <UTF8> chars are handled as whole strings */
+
+#include <stdio.h>
+#include <limits.h>
+#include <math.h>
+#include <R.h>
+
+static void f2xact(int nrow, int ncol, int *table, int ldtabl,
+		   double *expect, double *percnt, double *emin,
+		   double *prt, double *pre, double *fact, int *ico, int *iro,
+		   int *kyy, int *idif, int *irn, int *key,
+		   int *ldkey, int *ipoin, double *stp, int *ldstp,
+		   int *ifrq, double *LP, double *SP, double *tm,
+		   int *key2, int *iwk, double *rwk);
+static double f3xact(int nrow, int *irow, int ncol, int *icol, int ntot,
+		     double *fact, int *ico, int *iro,
+		     int *it, int *lb, int *nr, int *nt, int *nu,
+		     int *itc, int *ist, double *stv, double *alen,
+		     const double *tol);
+static double f4xact(int nrow, int *irow, int ncol, int *icol, double dspt,
+		     double *fact, int *icstk, int *ncstk,
+		     int *lstk, int *mstk, int *nstk, int *nrstk, int *irstk,
+		     double *ystk, const double *tol);
+static void f5xact(double *pastp, const double *tol, int *kval, int *key,
+		   int *ldkey, int *ipoin, double *stp, int *ldstp,
+		   int *ifrq, int *npoin, int *nr, int *nl, int *ifreq,
+		   int *itop, Rboolean psh);
+static Rboolean f6xact(int nrow, int *irow, int *kyy,
+		       int *key, int *ldkey, int *last, int *ipn);
+static void f7xact(int nrow, int *imax, int *idif, int *k, int *ks,
+		   int *iflag);
+static void f8xact(int *irow, int is, int i1, int izero, int *new);
+static double f9xact(int n, int ntot, int *ir, double *fact);
+static Rboolean f10act(int nrow, int *irow, int ncol, int *icol, double *val,
+		       double *fact, int *nd, int *ne, int *m);
+static void f11act(int *irow, int i1, int i2, int *new);
+static void NORET prterr(int icode, const char *mes);
+static int iwork(int iwkmax, int *iwkpt, int number, int itype);
+
+#ifdef USING_R
+# define isort(n, ix)		R_isort(ix, *n)
+# include <Rmath.h>	/* -> pgamma() */
+#else
+ static void isort(int *n, int *ix);
+ static double gammds(double *y, double *p, int *ifault);
+ static double alogam(double *x, int *ifault);
+#endif
+
+/* The only public function : */
+void
+fexact(int *nrow, int *ncol, int *table, int *ldtabl,
+       double *expect, double *percnt, double *emin, double *prt,
+       double *pre, /* new in C : */ int *workspace,
+       /* new arg, was const = 30*/int *mult)
+{
+
+/*
+  ALGORITHM 643, COLLECTED ALGORITHMS FROM ACM.
+  THIS WORK PUBLISHED IN TRANSACTIONS ON MATHEMATICAL SOFTWARE,
+  VOL. 19, NO. 4, DECEMBER, 1993, PP. 484-488.
+  -----------------------------------------------------------------------
+  Name:	      FEXACT
+  Purpose:    Computes Fisher's exact test probabilities and a hybrid
+	      approximation to Fisher exact test probabilities for a
+	      contingency table using the network algorithm.
+
+  Arguments:
+    NROW    - The number of rows in the table.			(Input)
+    NCOL    - The number of columns in the table.		(Input)
+    TABLE   - NROW by NCOL matrix containing the contingency
+	      table.						(Input)
+    LDTABL  - Leading dimension of TABLE exactly as specified
+	      in the dimension statement in the calling
+	      program.						(Input)
+    EXPECT  - Expected value used in the hybrid algorithm for
+	      deciding when to use asymptotic theory
+	      probabilities.					(Input)
+	      If EXPECT <= 0.0 then asymptotic theory probabilities
+	      are not used and Fisher exact test probabilities are
+	      computed.	 Otherwise, if PERCNT or more of the cells in
+	      the remaining table have estimated expected values of
+	      EXPECT or more, with no remaining cell having expected
+	      value less than EMIN, then asymptotic chi-squared
+	      probabilities are used.  See the algorithm section of the
+	      manual document for details.
+	      Use EXPECT = 5.0 to obtain the 'Cochran' condition.
+    PERCNT  - Percentage of remaining cells that must have
+	      estimated expected values greater than EXPECT
+	      before asymptotic probabilities can be used.	(Input)
+	      See argument EXPECT for details.
+	      Use PERCNT = 80.0 to obtain the 'Cochran' condition.
+    EMIN    - Minimum cell estimated expected value allowed for
+	      asymptotic chi-squared probabilities to be used.	(Input)
+	      See argument EXPECT for details.
+	      Use EMIN = 1.0 to obtain the 'Cochran' condition.
+    PRT     - Probability of the observed table for fixed
+	      marginal totals.					(Output)
+    PRE     - Table p-value.					(Output)
+	      PRE is the probability of a more extreme table,
+	      where `extreme' is in a probabilistic sense.
+	      If EXPECT < 0 then the Fisher exact probability
+	      is returned.  Otherwise, an approximation to the
+	      Fisher exact probability is computed based upon
+	      asymptotic chi-squared probabilities for ``large''
+	      table expected values.  The user defines ``large''
+	      through the arguments EXPECT, PERCNT, and EMIN.
+
+  Remarks:
+  1. For many problems one megabyte or more of workspace can be
+     required.	If the environment supports it, the user should begin
+     by increasing the workspace used to 200,000 units.
+  2. In FEXACT, LDSTP = MULT*LDKEY.  The proportion of table space used
+     by STP may be changed by changing the line MULT = 30 below to
+     another value. --> MULT is now an __argument__ of the function
+  3. FEXACT may be converted to single precision by setting IREAL = 3,
+     and converting all DOUBLE PRECISION specifications (except the
+     specifications for RWRK, IWRK, and DWRK) to REAL.	This will
+     require changing the names and specifications of the intrinsic
+     functions ALOG, AMAX1, AMIN1, EXP, and REAL.  In addition, the
+     machine specific constants will need to be changed, and the name
+     DWRK will need to be changed to RWRK in the call to F2XACT.
+  4. Machine specific constants are specified and documented in F2XACT.
+     A missing value code is specified in both FEXACT and F2XACT.
+  5. Although not a restriction, is is not generally practical to call
+     this routine with large tables which are not sparse and in
+     which the 'hybrid' algorithm has little effect.  For example,
+     although it is feasible to compute exact probabilities for the
+     table
+	    1 8 5 4 4 2 2
+	    5 3 3 4 3 1 0
+	   10 1 4 0 0 0 0,
+     computing exact probabilities for a similar table which has been
+     enlarged by the addition of an extra row (or column) may not be
+     feasible.
+  -----------------------------------------------------------------------
+  */
+
+    /* CONSTANT Parameters : */
+
+    /* To increase the length of the table of past path lengths relative
+       to the length of the hash table, increase MULT.
+    */
+
+    /* AMISS is a missing value indicator which is returned when the
+       probability is not defined.
+    */
+    const double amiss = -12345.;
+    /*
+      Set IREAL = 4 for DOUBLE PRECISION
+      Set IREAL = 3 for SINGLE PRECISION
+    */
+#define i_real 4
+#define i_int  2
+
+    /* System generated locals */
+    int ikh;
+    /* Local variables */
+    int nco, nro, ntot, numb, iiwk, irwk;
+    int i, j, k, kk, ldkey, ldstp, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10;
+    int i3a, i3b, i3c, i9a, iwkmax, iwkpt;
+
+    /* Workspace Allocation (freed when returning to R) */
+    double *equiv;
+    iwkmax = 2 * (int) (*workspace / 2);
+    equiv = (double *) R_alloc(iwkmax / 2, sizeof(double));
+
+#define dwrk (equiv)
+#define iwrk ((int *)equiv)
+#define rwrk ((float *)equiv)
+
+    /* Function Body */
+    iwkpt = 0;
+
+    if (*nrow > *ldtabl)
+	prterr(1, "NROW must be less than or equal to LDTABL.");
+
+    ntot = 0;
+    for (i = 0; i < *nrow; ++i) {
+	for (j = 0; j < *ncol; ++j) {
+	    if (table[i + j * *ldtabl] < 0)
+		prterr(2, "All elements of TABLE may not be negative.");
+	    ntot += table[i + j * *ldtabl];
+	}
+    }
+    if (ntot == 0) {
+	prterr(3, "All elements of TABLE are zero.\n"
+	       "PRT and PRE are set to missing values.");
+	*pre = *prt = amiss;
+	return;
+    }
+
+    /* nco := max(*nrow, *ncol)
+     * nro := min(*nrow, *ncol) */
+    if(*ncol > *nrow) {
+	nco = *ncol;
+	nro = *nrow;
+    } else {
+	nco = *nrow;
+	nro = *ncol;
+    }
+    k = *nrow + *ncol + 1;
+    kk = k * nco;
+
+    ikh = ntot + 1;
+    i1  = iwork(iwkmax, &iwkpt, ikh, i_real);
+    i2  = iwork(iwkmax, &iwkpt, nco, i_int);
+    i3  = iwork(iwkmax, &iwkpt, nco, i_int);
+    i3a = iwork(iwkmax, &iwkpt, nco, i_int);
+    i3b = iwork(iwkmax, &iwkpt, nro, i_int);
+    i3c = iwork(iwkmax, &iwkpt, nro, i_int);
+    ikh = imax2(k * 5 + (kk << 1), nco * 7 + 800);
+    iiwk= iwork(iwkmax, &iwkpt, ikh, i_int);
+    ikh = imax2(nco + 401, k);
+    irwk= iwork(iwkmax, &iwkpt, ikh, i_real);
+
+    /* NOTE:
+       What follows below splits the remaining amount iwkmax - iwkpt of
+       (int) workspace into hash tables as follows.
+	   type  size       index
+	   INT   2 * ldkey  i4 i5 i11
+	   REAL  2 * ldkey  i8 i9 i10
+	   REAL  2 * ldstp  i6
+	   INT   6 * ldstp  i7
+       Hence, we need ldkey times
+	   3 * 2 + 3 * 2 * s + 2 * mult * s + 6 * mult
+       chunks of integer memory, where s = sizeof(REAL) / sizeof(INT).
+       If doubles are used and are twice as long as ints, this gives
+	   18 + 10 * mult
+       so that the value of ldkey can be obtained by dividing available
+       (int) workspace by this number.
+
+       In fact, because iwork() can actually s * n + s - 1 int chunks
+       when allocating a REAL, we use ldkey = available / numb - 1.
+
+       FIXME:
+       Can we always assume that sizeof(double) / sizeof(int) is 2?
+       */
+
+    if (i_real == 4) {		/* Double precision reals */
+	numb = 18 + 10 * *mult;
+    } else {			/* Single precision reals */
+	numb = (*mult << 3) + 12;
+    }
+    ldkey = (iwkmax - iwkpt) / numb - 1;
+    ldstp = *mult * ldkey;
+    ikh = ldkey << 1;	i4  = iwork(iwkmax, &iwkpt, ikh, i_int);
+    ikh = ldkey << 1;	i5  = iwork(iwkmax, &iwkpt, ikh, i_int);
+    ikh = ldstp << 1;	i6  = iwork(iwkmax, &iwkpt, ikh, i_real);
+    ikh = ldstp * 6;	i7  = iwork(iwkmax, &iwkpt, ikh, i_int);
+    ikh = ldkey << 1;	i8  = iwork(iwkmax, &iwkpt, ikh, i_real);
+    ikh = ldkey << 1;	i9  = iwork(iwkmax, &iwkpt, ikh, i_real);
+    ikh = ldkey << 1;	i9a = iwork(iwkmax, &iwkpt, ikh, i_real);
+    ikh = ldkey << 1;	i10 = iwork(iwkmax, &iwkpt, ikh, i_int);
+
+
+    /* To convert to double precision, change RWRK to DWRK in the next CALL.
+     */
+    f2xact(*nrow,
+	   *ncol,
+	   table,
+	   *ldtabl,
+	   expect,
+	   percnt,
+	   emin,
+	   prt,
+	   pre,
+	   dwrk + i1,
+	   iwrk + i2,
+	   iwrk + i3,
+	   iwrk + i3a,
+	   iwrk + i3b,
+	   iwrk + i3c,
+	   iwrk + i4,
+	   &ldkey,
+	   iwrk + i5,
+	   dwrk + i6,
+	   &ldstp,
+	   iwrk + i7,
+	   dwrk + i8,
+	   dwrk + i9,
+	   dwrk + i9a,
+	   iwrk + i10,
+	   iwrk + iiwk,
+	   dwrk + irwk);
+
+    return;
+}
+
+#undef rwrk
+#undef iwrk
+#undef dwrk
+
+
+void
+f2xact(int nrow, int ncol, int *table, int ldtabl,
+       double *expect, double *percnt, double *emin, double *prt,
+       double *pre, double *fact, int *ico, int *iro, int *kyy,
+       int *idif, int *irn, int *key, int *ldkey, int *ipoin,
+       double *stp, int *ldstp, int *ifrq, double *LP, double *SP,
+       double *tm, int *key2, int *iwk, double *rwk)
+{
+/*
+  -----------------------------------------------------------------------
+  Name:		F2XACT
+  Purpose:	Computes Fisher's exact test for a contingency table,
+		routine with workspace variables specified.
+  -----------------------------------------------------------------------
+  */
+    const int imax = INT_MAX;/* the largest representable int on the machine.*/
+
+    /* AMISS is a missing value indicator which is returned when the
+       probability is not defined. */
+    const double amiss = -12345.;
+
+    /* TOL is chosen as the square root of the smallest relative spacing. */
+    const static double tol = 3.45254e-7;
+
+    const char* ch_err_5 =
+	"The hash table key cannot be computed because the largest key\n"
+	"is larger than the largest representable int.\n"
+	"The algorithm cannot proceed.\n"
+	"Reduce the workspace size or use another algorithm.";
+
+    /* Local variables -- changed from "static"
+     *  (*does* change results very slightly on i386 linux) */
+    int i, ii, j, k, n,
+	iflag,ifreq, ikkey, ikstp, ikstp2, ipn, ipo, itop, itp = 0,
+	jkey, jstp, jstp2, jstp3, jstp4, k1, kb, kd, ks, kval = 0, kmax, last,
+	ncell, ntot, nco, nro, nro2, nrb,
+	i31, i32, i33, i34, i35, i36, i37, i38, i39,
+	i41, i42, i43, i44, i45, i46, i47, i48, i310, i311;
+
+    double dspt, d1,dd,df,ddf, drn,dro, obs, obs2, obs3, pastp,pv, tmp=0.;
+
+#ifndef USING_R
+    double d2;
+    int ifault;
+#endif
+    Rboolean nr_gt_nc, maybe_chisq, chisq = FALSE/* -Wall */, psh;
+
+    /* Parameter adjustments */
+    table -= ldtabl + 1;
+    --ico;
+    --iro;
+    --kyy;
+    --idif;
+    --irn;
+
+    --key;
+    --ipoin;
+    --stp;
+    --ifrq;
+    --LP;
+    --SP;
+    --tm;
+    --key2;
+    --iwk;
+    --rwk;
+
+
+    /* Check table dimensions */
+    if (nrow > ldtabl)
+	prterr(1, "NROW must be less than or equal to LDTABL.");
+    if (ncol <= 1)
+	prterr(4, "NCOL must be at least 2");
+
+    /* Initialize KEY array */
+    for (i = 1; i <= *ldkey << 1; ++i) {
+	key[i] = -9999;
+	key2[i] = -9999;
+    }
+
+    nr_gt_nc =  nrow > ncol;
+    /* nco := max(nrow, ncol) : */
+    if(nr_gt_nc)
+	nco = nrow;
+    else
+	nco = ncol;
+    /* Compute row marginals and total */
+    ntot = 0;
+    for (i = 1; i <= nrow; ++i) {
+	iro[i] = 0;
+	for (j = 1; j <= ncol; ++j) {
+	    if (table[i + j * ldtabl] < 0.)
+		prterr(2, "All elements of TABLE may not be negative.");
+	    iro[i] += table[i + j * ldtabl];
+	}
+	ntot += iro[i];
+    }
+
+    if (ntot == 0) {
+	prterr(3, "All elements of TABLE are zero.\n"
+	       "PRT and PRE are set to missing values.");
+	*pre = *prt = amiss;
+	return;
+    }
+
+    /* Column marginals */
+    for (i = 1; i <= ncol; ++i) {
+	ico[i] = 0;
+	for (j = 1; j <= nrow; ++j)
+	    ico[i] += table[j + i * ldtabl];
+    }
+
+    /* sort marginals */
+    isort(&nrow, &iro[1]);
+    isort(&ncol, &ico[1]);
+
+    /*	Determine row and column marginals.
+	Define max(nrow,ncol) =: nco >= nro := min(nrow,ncol)
+	nco is defined above
+
+	Swap marginals if necessary to	ico[1:nco] & iro[1:nro]
+     */
+    if (nr_gt_nc) {
+	nro = ncol;
+	/* Swap marginals */
+	for (i = 1; i <= nco; ++i) {
+	    ii = iro[i];
+	    if (i <= nro)
+		iro[i] = ico[i];
+	    ico[i] = ii;
+	}
+    } else
+	nro = nrow;
+
+    /* Get multiplers for stack */
+    kyy[1] = 1;
+    for (i = 1; i < nro; ++i) {
+	/* Hash table multipliers */
+	if (iro[i] + 1 <= imax / kyy[i]) {
+	    kyy[i + 1] = kyy[i] * (iro[i] + 1);
+	    j /= kyy[i];
+	}
+	else {
+	    prterr(5, ch_err_5);
+	    return;
+	}
+    }
+
+    /* Check for Maximum product : */
+    /* original code: if (iro[nro - 1] + 1 > imax / kyy[nro - 1]) */
+    if (iro[nro] + 1 > imax / kyy[nro]) {
+	/* L_ERR_5: */
+	prterr(501, ch_err_5);
+	return;
+    }
+
+    /* Compute log factorials */
+    fact[0] = 0.;
+    fact[1] = 0.;
+    if(ntot >= 2) fact[2] = log(2.);
+    /* MM: old code assuming log() to be SLOW */
+    for (i = 3; i <= ntot; i += 2) {
+	fact[i] = fact[i - 1] + log((double) i);
+	j = i + 1;
+	if (j <= ntot)
+	    fact[j] = fact[i] + fact[2] + fact[j / 2] - fact[j / 2 - 1];
+    }
+    /* Compute obs := observed path length */
+    obs = tol;
+    ntot = 0;
+    for (j = 1; j <= nco; ++j) {
+	dd = 0.;
+	if (nr_gt_nc) {
+	    for (i = 1; i <= nro; ++i) {
+		dd += fact[table[j + i * ldtabl]];
+		ntot +=    table[j + i * ldtabl];
+	    }
+	} else {
+	    for (i = 1, ii = j * ldtabl + 1; i <= nro; i++, ii++) {
+		dd += fact[table[ii]];
+		ntot +=    table[ii];
+	    }
+	}
+	obs += fact[ico[j]] - dd;
+    }
+
+    /* Denominator of observed table: DRO */
+    dro = f9xact(nro, ntot, &iro[1], fact);
+    /* improve: the following "easily" underflows to zero -- return "log()" */
+    *prt = exp(obs - dro);
+    *pre = 0.;
+    itop = 0;
+    maybe_chisq = (*expect > 0.);
+
+    /* Initialize pointers for workspace */
+    /* f3xact */
+    i31 = 1;
+    i32 = i31 + nco;
+    i33 = i32 + nco;
+    i34 = i33 + nco;
+    i35 = i34 + nco;
+    i36 = i35 + nco;
+    i37 = i36 + nco;
+    i38 = i37 + nco;
+    i39 = i38 + 400;
+    i310 = 1;
+    i311 = 1 + 400;
+    /* f4xact */
+    i = nrow + ncol + 1;
+    i41 = 1;
+    i42 = i41 + i;
+    i43 = i42 + i;
+    i44 = i43 + i;
+    i45 = i44 + i;
+    i46 = i45 + i;
+    i47 = i46 + i * nco;
+    i48 = 1;
+
+    /* Initialize pointers */
+    k = nco;
+    last = *ldkey + 1;
+    jkey = *ldkey + 1;
+    jstp = *ldstp + 1;
+    jstp2 = *ldstp * 3 + 1;
+    jstp3 = (*ldstp << 2) + 1;
+    jstp4 = *ldstp * 5 + 1;
+    ikkey = 0;
+    ikstp = 0;
+    ikstp2 = *ldstp << 1;
+    ipo = 1;
+    ipoin[1] = 1;
+    stp[1] = 0.;
+    ifrq[1] = 1;
+    ifrq[ikstp2 + 1] = -1;
+
+Outer_Loop:
+    kb = nco - k + 1;
+    ks = 0;
+    n = ico[kb];
+    kd = nro + 1;
+    kmax = nro;
+    /* IDIF is the difference in going to the daughter */
+    for (i = 1; i <= nro; ++i)
+	idif[i] = 0;
+
+    /* Generate the first daughter */
+    do {
+	--kd;
+	ntot = imin2(n, iro[kd]);
+	idif[kd] = ntot;
+	if (idif[kmax] == 0)
+	    --kmax;
+	n -= ntot;
+
+    } while (n > 0 && kd != 1);
+
+    if (n != 0) /* i.e. kd == 1 */
+	goto L310;
+
+
+    k1 = k - 1;
+    n = ico[kb];
+    ntot = 0;
+    for (i = kb + 1; i <= nco; ++i)
+	ntot += ico[i];
+
+
+L150:
+    /* Arc to daughter length=ICO[KB] */
+    for (i = 1; i <= nro; ++i)
+	irn[i] = iro[i] - idif[i];
+
+    if (k1 > 1) {
+	/* Sort irn */
+	if (nro == 2) {
+	    if (irn[1] > irn[2]) {
+		ii = irn[1]; irn[1] = irn[2]; irn[2] = ii;
+	    }
+	} else
+	    isort(&nro, &irn[1]);
+
+	/* Adjust start for zero */
+	for (i = 1; i <= nro; ++i) {
+	    if (irn[i] != 0)
+		break;
+	}
+	nrb = i;
+    }
+    else {
+	nrb = 1;
+    }
+    nro2 = nro - nrb + 1;
+
+    /* Some table values */
+    ddf = f9xact(nro,  n,    &idif[1],  fact);
+    drn = f9xact(nro2, ntot, &irn[nrb], fact) - dro + ddf;
+    /* Get hash value */
+    if (k1 > 1) {
+	kval = irn[1];
+	/* Note that with the corrected check at error "502",
+	 * we won't have overflow in  kval  below : */
+	for (i = 2; i <= nro; ++i)
+	    kval += irn[i] * kyy[i];
+
+	/* Get hash table entry */
+	i = kval % (*ldkey << 1) + 1;
+	/* Search for unused location */
+	for (itp = i; itp <= *ldkey << 1; ++itp) {
+	    ii = key2[itp];
+	    if (ii == kval) {
+		goto L240;
+	    } else if (ii < 0) {
+		key2[itp] = kval;
+		LP[itp] = 1.;
+		SP[itp] = 1.;
+		goto L240;
+	    }
+	}
+
+	for (itp = 1; itp <= i - 1; ++itp) {
+	    ii = key2[itp];
+	    if (ii == kval) {
+		goto L240;
+	    } else if (ii < 0) {
+		key2[itp] = kval;
+		LP[itp] = 1.;
+		goto L240;
+	    }
+	}
+
+	/* KH
+	   prterr(6, "LDKEY is too small.\n"
+	   "It is not possible to give the value of LDKEY required,\n"
+	   "but you could try doubling LDKEY (and possibly LDSTP).");
+	   */
+	prterr(6, "LDKEY is too small for this problem.\n"
+	       "Try increasing the size of the workspace.");
+    }
+
+L240:
+    psh = TRUE;
+    /* Recover pastp */
+    ipn = ipoin[ipo + ikkey];
+    pastp = stp[ipn + ikstp];
+    ifreq = ifrq[ipn + ikstp];
+    /* Compute shortest and longest path */
+    if (k1 > 1) {
+	obs2 = obs - fact[ico[kb + 1]] - fact[ico[kb + 2]] - ddf;
+	for (i = 3; i <= k1; ++i)
+	    obs2 -= fact[ico[kb + i]];
+
+	if (LP[itp] > 0.) {
+	    dspt = obs - obs2 - ddf;
+	    /* Compute longest path */
+	    LP[itp] = f3xact(nro2, &irn[nrb], k1, &ico[kb + 1], ntot, fact,
+			      &iwk[i31], &iwk[i32], &iwk[i33], &iwk[i34],
+			      &iwk[i35], &iwk[i36], &iwk[i37], &iwk[i38],
+			      &iwk[i39], &rwk[i310], &rwk[i311], &tol);
+	    if(LP[itp] > 0.) {/* can this happen? */
+		REprintf("___ LP[itp=%d] = %g > 0\n", itp, LP[itp]);
+		LP[itp] = 0.;
+	    }
+
+	    /* Compute shortest path -- using  dspt  as offset */
+	    SP[itp] = f4xact(nro2, &irn[nrb], k1, &ico[kb + 1], dspt, fact,
+			      &iwk[i47], &iwk[i41], &iwk[i42], &iwk[i43],
+			      &iwk[i44], &iwk[i45], &iwk[i46], &rwk[i48], &tol);
+	    /* SP[itp] = fmin2(0., SP[itp] - dspt);*/
+	    if(SP[itp] > 0.) { /* can this happen? */
+		REprintf("___ SP[itp=%d] = %g > 0\n", itp, SP[itp]);
+		SP[itp] = 0.;
+	    }
+
+	    /* Use chi-squared approximation? */
+	    if (maybe_chisq && (irn[nrb] * ico[kb + 1]) > ntot * *emin) {
+		ncell = 0.;
+		for (i = 0; i < nro2; ++i)
+		    for (j = 1; j <= k1; ++j)
+			if (irn[nrb + i] * ico[kb + j] >= ntot * *expect)
+			    ncell++;
+
+		if (ncell * 100 >= k1 * nro2 * *percnt) {
+		    tmp = 0.;
+		    for (i = 0; i < nro2; ++i)
+			tmp += (fact[irn[nrb + i]] -
+				fact[irn[nrb + i] - 1]);
+		    tmp *= k1 - 1;
+		    for (j = 1; j <= k1; ++j)
+			tmp += (nro2 - 1) * (fact[ico[kb + j]] -
+					     fact[ico[kb + j] - 1]);
+		    df = (double) ((nro2 - 1) * (k1 - 1));
+		    tmp += df * 1.83787706640934548356065947281;
+		    tmp -= (nro2 * k1 - 1) * (fact[ntot] - fact[ntot - 1]);
+		    tm[itp] = (obs - dro) * -2. - tmp;
+		} else {
+		    /* tm[itp] set to a flag value */
+		    tm[itp] = -9876.;
+		}
+	    } else {
+		tm[itp] = -9876.;
+	    }
+	}
+	obs3 = obs2 - LP[itp];
+	obs2 -= SP[itp];
+	if (tm[itp] == -9876.) {
+	    chisq = FALSE;
+	} else {
+	    chisq = TRUE;
+	    tmp = tm[itp];
+	}
+    } else {
+	obs2 = obs - drn - dro;
+	obs3 = obs2;
+    }
+
+L300:
+    /* Process node with new PASTP */
+    if (pastp <= obs3) {
+	/* Update pre */
+	*pre += (double) ifreq * exp(pastp + drn);
+    } else if (pastp < obs2) {
+	if (chisq) {
+	    df = (double) ((nro2 - 1) * (k1 - 1));
+#ifdef USING_R
+	    pv = pgamma(fmax2(0., tmp + (pastp + drn) * 2.) / 2.,
+			df / 2., /*scale = */ 1.,
+			/*lower_tail = */FALSE, /*log_p = */ FALSE);
+#else
+	    d1 = fmax2(0., tmp + (pastp + drn) * 2.) / 2.;
+	    d2 = df / 2.;
+	    pv = 1. - gammds(&d1, &d2, &ifault);
+#endif
+	    *pre += (double) ifreq * exp(pastp + drn) * pv;
+	} else {
+	    /* Put daughter on queue */
+	    d1 = pastp + ddf;
+	    f5xact(&d1, &tol, &kval, &key[jkey], ldkey, &ipoin[jkey],
+		   &stp[jstp], ldstp, &ifrq[jstp], &ifrq[jstp2],
+		   &ifrq[jstp3], &ifrq[jstp4], &ifreq, &itop, psh);
+	    psh = FALSE;
+	}
+    }
+    /* Get next PASTP on chain */
+    ipn = ifrq[ipn + ikstp2];
+    if (ipn > 0) {
+	pastp = stp[ipn + ikstp];
+	ifreq = ifrq[ipn + ikstp];
+	goto L300;
+    }
+    /* Generate a new daughter node */
+    f7xact(kmax, &iro[1], &idif[1], &kd, &ks, &iflag);
+    if (iflag != 1)
+	goto L150;
+
+
+L310:
+    /* Go get a new mother from stage K */
+    do {
+	if(!f6xact(nro, &iro[1], &kyy[1], &key[ikkey + 1], ldkey, &last, &ipo))
+	    /* Update pointers */
+	    goto Outer_Loop;
+
+	/* else : no additional nodes to process */
+	--k;
+	itop = 0;
+	ikkey = jkey - 1;
+	ikstp = jstp - 1;
+	ikstp2 = jstp2 - 1;
+	jkey = *ldkey - jkey + 2;
+	jstp = *ldstp - jstp + 2;
+	jstp2 = (*ldstp << 1) + jstp;
+	for (i = 1; i <= *ldkey << 1; ++i)
+	    key2[i] = -9999;
+
+    } while (k >= 2);
+
+}/* f2xact() */
+
+
+double
+f3xact(int nrow, int *irow, int ncol, int *icol,
+       int ntot, double *fact, int *ico, int *iro, int *it,
+       int *lb, int *nr, int *nt, int *nu, int *itc, int *ist,
+       double *stv, double *alen, const double *tol)
+{
+/*
+ -----------------------------------------------------------------------
+  Name:	      F3XACT
+  Purpose:    Computes the longest path length for a given table.
+
+  Arguments:
+    NROW    - The number of rows in the table.			(Input)
+    IROW    - Vector of length NROW containing the row sums
+	      for the table.					(Input)
+    NCOL    - The number of columns in the table.		(Input)
+    ICOL    - Vector of length K containing the column sums
+	      for the table.					(Input)
+    NTOT    - The total count in the table.			(Input)
+    FACT    - Vector containing the logarithms of factorials.	(Input)
+    ICO     - Work vector of length MAX(NROW,NCOL).
+    IRO     - Work vector of length MAX(NROW,NCOL).
+    IT	    - Work vector of length MAX(NROW,NCOL).
+    LB	    - Work vector of length MAX(NROW,NCOL).
+    NR	    - Work vector of length MAX(NROW,NCOL).
+    NT	    - Work vector of length MAX(NROW,NCOL).
+    NU	    - Work vector of length MAX(NROW,NCOL).
+    ITC     - Work vector of length 400.
+    IST     - Work vector of length 400.
+    STV     - Work vector of length 400.
+    ALEN    - Work vector of length MAX(NROW,NCOL).
+    TOL     - Tolerance.					(Input)
+
+  Return Value :
+    LP     - The longest path for the table.			(Output)
+
+  -----------------------------------------------------------------------
+  */
+
+    const int ldst = 200;/* half stack size */
+    /* Initialized data */
+    static int nst = 0;
+    static int nitc = 0;
+
+    /* Local variables */
+    int i, k;
+    int n11, n12, ii, nn, ks, ic1, ic2, nc1, nn1;
+    int nr1, nco, nct, ipn, irl, key, lev, itp, nro, nrt, kyy, nc1s;
+    double LP, v, val, vmn;
+    Rboolean xmin;
+
+    /* Parameter adjustments */
+    --stv;
+    --ist;
+    --itc;
+    --nu;
+    --nt;
+    --nr;
+    --lb;
+    --it;
+    --iro;
+    --ico;
+    --icol;
+    --irow;
+
+    if (nrow <= 1) {	/* nrow is 1 */
+	LP = 0.;
+	if (nrow > 0) {
+	    for (i = 1; i <= ncol; ++i)
+		LP -= fact[icol[i]];
+	}
+	return LP;
+    }
+
+    if (ncol <= 1) {	/* ncol is 1 */
+	LP = 0.;
+	if (ncol > 0) {
+	    for (i = 1; i <= nrow; ++i)
+		LP -= fact[irow[i]];
+	}
+	return LP;
+    }
+
+    /* 2 by 2 table */
+    if (nrow * ncol == 4) {
+	n11 = (irow[1] + 1) * (icol[1] + 1) / (ntot + 2);
+	n12 = irow[1] - n11;
+	return -(fact[n11] + fact[n12] +
+		 fact[icol[1] - n11] + fact[icol[2] - n12]);
+    }
+
+    /* ELSE:  larger than 2 x 2 : */
+
+    /* Test for optimal table */
+    val = 0.;
+    if (irow[nrow] <= irow[1] + ncol) {
+	xmin = f10act(nrow, &irow[1], ncol, &icol[1], &val, fact,
+		      &lb[1], &nu[1], &nr[1]);
+    } else xmin = FALSE;
+    if (! xmin &&  icol[ncol] <= icol[1] + nrow) {
+	xmin = f10act(ncol, &icol[1], nrow, &irow[1], &val, fact,
+		      &lb[1], &nu[1], &nr[1]);
+    }
+    if (xmin)
+	return  - val;
+
+
+    /* Setup for dynamic programming */
+
+    for (i = 0; i <= ncol; ++i)
+	alen[i] = 0.;
+    for (i = 1; i <= 2*ldst; ++i)
+	ist[i] = -1;
+
+    nn = ntot;
+    /* Minimize ncol */
+    if (nrow >= ncol) {
+	nro = nrow;
+	nco = ncol;
+	ico[1] = icol[1];
+	nt[1] = nn - ico[1];
+	for (i = 2; i <= ncol; ++i) {
+	    ico[i] = icol[i];
+	    nt[i] = nt[i - 1] - ico[i];
+	}
+	for (i = 1; i <= nrow; ++i)
+	    iro[i] = irow[i];
+
+    } else {
+	nro = ncol;
+	nco = nrow;
+	ico[1] = irow[1];
+	nt[1] = nn - ico[1];
+	for (i = 2; i <= nrow; ++i) {
+	    ico[i] = irow[i];
+	    nt[i] = nt[i - 1] - ico[i];
+	}
+	for (i = 1; i <= ncol; ++i)
+	    iro[i] = icol[i];
+    }
+
+    nc1s = nco - 1;
+    kyy = ico[nco] + 1;
+    /* Initialize pointers */
+    vmn = 1e100;/* to contain min(v..) */
+    irl = 1;
+    ks = 0;
+    k = ldst;
+
+
+LnewNode: /* Setup to generate new node */
+
+    lev = 1;
+    nr1 = nro - 1;
+    nrt = iro[irl];
+    nct = ico[1];
+    lb[1] = (int) ((((double) nrt + 1) * (nct + 1)) /
+		    (double) (nn + nr1 * nc1s + 1) - *tol) - 1;
+    nu[1] = (int) ((((double) nrt + nc1s) * (nct + nr1)) /
+		    (double) (nn + nr1 + nc1s)) - lb[1] + 1;
+    nr[1] = nrt - lb[1];
+
+LoopNode: /* Generate a node */
+    --nu[lev];
+    if (nu[lev] == 0) {
+	if (lev == 1)
+	    goto L200;
+
+	--lev;
+	goto LoopNode;
+    }
+    ++lb[lev];
+    --nr[lev];
+
+    while(1) {
+	alen[lev] = alen[lev - 1] + fact[lb[lev]];
+	if (lev >= nc1s)
+	    break;
+
+	nn1 = nt[lev];
+	nrt = nr[lev];
+	++lev;
+	nc1 = nco - lev;
+	nct = ico[lev];
+	lb[lev] = (int) ((((double) nrt + 1) * (nct + 1)) /
+			  (double) (nn1 + nr1 * nc1 + 1) - *tol);
+	nu[lev] = (int) ((((double) nrt + nc1) * (nct + nr1)) /
+			  (double) (nn1 + nr1 + nc1) - lb[lev] + 1);
+	nr[lev] = nrt - lb[lev];
+    }
+    alen[nco] = alen[lev] + fact[nr[lev]];
+    lb[nco] = nr[lev];
+
+    v = val + alen[nco];
+
+    if (nro == 2) { /* Only 1 row left */
+	v += fact[ico[1] - lb[1]] + fact[ico[2] - lb[2]];
+	for (i = 3; i <= nco; ++i)
+	    v += fact[ico[i] - lb[i]];
+
+	if (v < vmn)
+	    vmn = v;
+
+    } else if (nro == 3 && nco == 2) { /* 3 rows and 2 columns */
+	nn1 = nn - iro[irl] + 2;
+	ic1 = ico[1] - lb[1];
+	ic2 = ico[2] - lb[2];
+	n11 = (iro[irl + 1] + 1) * (ic1 + 1) / nn1;
+	n12 = iro[irl + 1] - n11;
+	v += fact[n11] + fact[n12] + fact[ic1 - n11] + fact[ic2 - n12];
+	if (v < vmn)
+	    vmn = v;
+
+    } else { /* Column marginals are new node */
+
+	for (i = 1; i <= nco; ++i)
+	    it[i] = imax2(ico[i] - lb[i], 0);
+
+	/* Sort column marginals it[] : */
+	if (nco == 2) {
+	    if (it[1] > it[2]) { /* swap */
+		ii = it[1]; it[1] = it[2]; it[2] = ii;
+	    }
+	} else
+	    isort(&nco, &it[1]);
+
+	/* Compute hash value */
+	key = it[1] * kyy + it[2];
+	for (i = 3; i <= nco; ++i) {
+	    key = it[i] + key * kyy;
+	}
+	if (key < -1)
+	    PROBLEM "Bug in FEXACT: gave negative key" RECOVER(NULL_ENTRY);
+	/* Table index */
+	ipn = key % ldst + 1;
+	/* Find empty position */
+	for (itp = ipn, ii = ks + ipn; itp <= ldst; ++itp, ++ii) {
+	    if (ist[ii] < 0) {
+		goto L180;
+	    } else if (ist[ii] == key) {
+		goto L190;
+	    }
+	}
+
+	for (itp = 1, ii = ks + 1; itp <= ipn - 1; ++itp, ++ii) {
+	    if (ist[ii] < 0) {
+		goto L180;
+	    } else if (ist[ii] == key) {
+		goto L190;
+	    }
+	}
+
+	/* this happens less, now that we check for negative key above: */
+	prterr(30, "Stack length exceeded in f3xact.\n"
+	       "This problem should not occur.");
+
+L180: /* Push onto stack */
+	ist[ii] = key;
+	stv[ii] = v;
+	++nst;
+	ii = nst + ks;
+	itc[ii] = itp;
+	goto LoopNode;
+
+L190: /* Marginals already on stack */
+	stv[ii] = fmin2(v, stv[ii]);
+    }
+    goto LoopNode;
+
+
+L200: /* Pop item from stack */
+    if (nitc > 0) {
+	/* Stack index */
+	itp = itc[nitc + k] + k;
+	--nitc;
+	val = stv[itp];
+	key = ist[itp];
+	ist[itp] = -1;
+	/* Compute marginals */
+	for (i = nco; i >= 2; --i) {
+	    ico[i] = key % kyy;
+	    key /= kyy;
+	}
+	ico[1] = key;
+	/* Set up nt array */
+	nt[1] = nn - ico[1];
+	for (i = 2; i <= nco; ++i)
+	    nt[i] = nt[i - 1] - ico[i];
+
+	/* Test for optimality (L90) */
+	if (iro[nro] <= iro[irl] + nco) {
+	    xmin = f10act(nro, &iro[irl], nco, &ico[1], &val, fact,
+			  &lb[1], &nu[1], &nr[1]);
+	} else xmin = FALSE;
+
+	if (!xmin && ico[nco] <= ico[1] + nro)
+	    xmin = f10act(nco, &ico[1], nro, &iro[irl], &val, fact,
+			  &lb[1], &nu[1], &nr[1]);
+	if (xmin) {
+	    if (vmn > val)
+		vmn = val;
+	    goto L200;
+	}
+	else goto LnewNode;
+
+    } else if (nro > 2 && nst > 0) {
+	/* Go to next level */
+	nitc = nst;
+	nst = 0;
+	k = ks;
+	ks = ldst - ks;
+	nn -= iro[irl];
+	++irl;
+	--nro;
+	goto L200;
+    }
+
+    return  - vmn;
+}
+
+double
+f4xact(int nrow, int *irow, int ncol, int *icol, double dspt,
+       double *fact, int *icstk, int *ncstk, int *lstk, int *mstk,
+       int *nstk, int *nrstk, int *irstk, double *ystk, const double *tol)
+{
+/*
+  -----------------------------------------------------------------------
+  Name:	      F4XACT
+  Purpose:    Computes the shortest path length for a given table.
+
+  Arguments:
+     NROW   - The number of rows in the table.	(Input)
+     IROW   - Vector of length NROW containing the row sums for the
+	      table.  (Input)
+     NCOL   - The number of columns in the table.  (Input)
+     ICOL   - Vector of length K containing the column sums for the
+	      table.  (Input)
+     DSPT   - "offset"  for SP computation
+     FACT   - Vector containing the logarithms of factorials.  (Input)
+     ICSTK  - NCOL by NROW+NCOL+1 work array.
+     NCSTK  - Work vector of length NROW+NCOL+1.
+     LSTK   - Work vector of length NROW+NCOL+1.
+     MSTK   - Work vector of length NROW+NCOL+1.
+     NSTK   - Work vector of length NROW+NCOL+1.
+     NRSTK  - Work vector of length NROW+NCOL+1.
+     IRSTK  - NROW by MAX(NROW,NCOL) work array.
+     YSTK   - Work vector of length NROW+NCOL+1.
+     TOL    - Tolerance.					(Input)
+
+  Return Value :
+
+    SP	    - The shortest path for the table.			(Output)
+  -----------------------------------------------------------------------
+  */
+
+    /* Local variables */
+    int i, j, k, l, m, n, ic1, ir1, ict, irt, istk, nco, nro;
+    double y, amx, SP;
+
+    /* Take care of the easy cases first */
+    if (nrow == 1) {
+	SP = 0.;
+	for (i = 0; i < ncol; ++i)
+	    SP -= fact[icol[i]];
+	return SP;
+    }
+    if (ncol == 1) {
+	SP = 0.;
+	for (i = 0; i < nrow; ++i)
+	    SP -= fact[irow[i]];
+	return SP;
+    }
+    if (nrow * ncol == 4) {
+	if (irow[1] <= icol[1])
+	    return -(fact[irow[1]] + fact[icol[1]] + fact[icol[1] - irow[1]]);
+	else
+	    return -(fact[icol[1]] + fact[irow[1]] + fact[irow[1] - icol[1]]);
+    }
+
+    /* Parameter adjustments */
+    irstk -= nrow + 1;
+    icstk -= ncol + 1;
+
+    --nrstk;
+    --ncstk;
+    --lstk;
+    --mstk;
+    --nstk;
+    --ystk;
+
+    /* initialization before loop */
+    for (i = 1; i <= nrow; ++i)
+	irstk[i + nrow] = irow[nrow - i];
+
+    for (j = 1; j <= ncol; ++j)
+	icstk[j + ncol] = icol[ncol - j];
+
+    nro = nrow;
+    nco = ncol;
+    nrstk[1] = nro;
+    ncstk[1] = nco;
+    ystk[1] = 0.;
+    y = 0.;
+    istk = 1;
+    l = 1;
+    amx = 0.;
+    SP = dspt;
+
+    /* First LOOP */
+    do {
+	ir1 = irstk[istk * nrow + 1];
+	ic1 = icstk[istk * ncol + 1];
+	if (ir1 > ic1) {
+	    if (nro >= nco) {
+		m = nco - 1;	n = 2;
+	    } else {
+		m = nro;	n = 1;
+	    }
+	} else if (ir1 < ic1) {
+	    if (nro <= nco) {
+		m = nro - 1;	n = 1;
+	    } else {
+		m = nco;	n = 2;
+	    }
+	} else {
+	    if (nro <= nco) {
+		m = nro - 1;	n = 1;
+	    } else {
+		m = nco - 1;	n = 2;
+	    }
+	}
+
+    L60:
+	if (n == 1) {
+	    i = l; j = 1;
+	} else {
+	    i = 1; j = l;
+	}
+
+	irt = irstk[i + istk * nrow];
+	ict = icstk[j + istk * ncol];
+	y += fact[imin2(irt, ict)];
+	if (irt == ict) {
+	    --nro;
+	    --nco;
+	    f11act(&irstk[istk * nrow + 1], i, nro,
+		   &irstk[(istk + 1) * nrow + 1]);
+	    f11act(&icstk[istk * ncol + 1], j, nco,
+		   &icstk[(istk + 1) * ncol + 1]);
+	} else if (irt > ict) {
+	    --nco;
+	    f11act(&icstk[istk * ncol + 1], j, nco,
+		   &icstk[(istk + 1) * ncol + 1]);
+	    f8xact(&irstk[istk * nrow + 1], irt - ict, i, nro,
+		   &irstk[(istk + 1) * nrow + 1]);
+	} else {
+	    --nro;
+	    f11act(&irstk[istk * nrow + 1], i, nro,
+		   &irstk[(istk + 1) * nrow + 1]);
+	    f8xact(&icstk[istk * ncol + 1], ict - irt, j, nco,
+		   &icstk[(istk + 1) * ncol + 1]);
+	}
+
+	if (nro == 1) {
+	    for (k = 1; k <= nco; ++k)
+		y += fact[icstk[k + (istk + 1) * ncol]];
+	    break;
+	}
+	if (nco == 1) {
+	    for (k = 1; k <= nro; ++k)
+		y += fact[irstk[k + (istk + 1) * nrow]];
+	    break;
+	}
+
+	lstk[istk] = l;
+	mstk[istk] = m;
+	nstk[istk] = n;
+	++istk;
+	nrstk[istk] = nro;
+	ncstk[istk] = nco;
+	ystk[istk] = y;
+	l = 1;
+    } while(1);/* end do */
+
+/* L90:*/
+    if (y > amx) {
+	amx = y;
+	if (SP - amx <= *tol)
+	    return -dspt;
+    }
+
+/* L100: */
+    do {
+	--istk;
+	if (istk == 0) {
+	    SP -= amx;
+	    if (SP - amx <= *tol)
+		return -dspt;
+	    else
+		return SP - dspt;
+	}
+	l = lstk[istk] + 1;
+
+	/* L110: */
+	for(;; ++l) {
+	    if (l > mstk[istk])	break;
+
+	    n = nstk[istk];
+	    nro = nrstk[istk];
+	    nco = ncstk[istk];
+	    y = ystk[istk];
+	    if (n == 1) {
+		if (irstk[l	+ istk * nrow] <
+		    irstk[l - 1 + istk * nrow])	goto L60;
+	    }
+	    else if (n == 2) {
+		if (icstk[l	+ istk * ncol] <
+		    icstk[l - 1 + istk * ncol])	goto L60;
+	    }
+	}
+    } while(1);
+}
+
+
+void
+f5xact(double *pastp, const double *tol, int *kval, int *key, int *ldkey,
+       int *ipoin, double *stp, int *ldstp, int *ifrq, int *npoin,
+       int *nr, int *nl, int *ifreq, int *itop, Rboolean psh)
+{
+/*
+  -----------------------------------------------------------------------
+  Name:	      F5XACT aka "PUT"
+  Purpose:    Put node on stack in network algorithm.
+
+  Arguments:
+     PASTP  - The past path length.				(Input)
+     TOL    - Tolerance for equivalence of past path lengths.	(Input)
+     KVAL   - Key value.					(Input)
+     KEY    - Vector of length LDKEY containing the key values.	(in/out)
+     LDKEY  - Length of vector KEY.				(Input)
+     IPOIN  - Vector of length LDKEY pointing to the
+	      linked list of past path lengths.		(in/out)
+     STP    - Vector of length LSDTP containing the
+	      linked lists of past path lengths.		(in/out)
+     LDSTP  - Length of vector STP.				(Input)
+     IFRQ   - Vector of length LDSTP containing the past path
+	      frequencies.					(in/out)
+     NPOIN  - Vector of length LDSTP containing the pointers to
+	      the next past path length.			(in/out)
+     NR	    - Vector of length LDSTP containing the right object
+	      pointers in the tree of past path lengths.        (in/out)
+     NL	    - Vector of length LDSTP containing the left object
+	      pointers in the tree of past path lengths.        (in/out)
+     IFREQ  - Frequency of the current path length.             (Input)
+     ITOP   - Pointer to the top of STP.			(Input)
+     PSH    - Logical.						(Input)
+	      If PSH is true, the past path length is found in the
+	      table KEY.  Otherwise the location of the past path
+	      length is assumed known and to have been found in
+	      a previous call. ==>>>>> USING "static" variables
+  -----------------------------------------------------------------------
+  */
+
+    /* Local variables */
+    static int itmp, ird, ipn, itp; /* << *need* static, see PSH above */
+    double test1, test2;
+
+    /* Parameter adjustments */
+    --nl;
+    --nr;
+    --npoin;
+    --ifrq;
+    --stp;
+
+    /* Function Body */
+    if (psh) {
+	/* Convert KVAL to int in range 1, ..., LDKEY. */
+	ird = *kval % *ldkey;
+	/* Search for an unused location */
+	for (itp = ird; itp < *ldkey; ++itp) {
+	    if (key[itp] == *kval)
+		goto L40;
+
+	    if (key[itp] < 0)
+		goto L30;
+	}
+	for (itp = 0; itp < ird; ++itp) {
+	    if (key[itp] == *kval)
+		goto L40;
+
+	    if (key[itp] < 0)
+		goto L30;
+	}
+	/* Return if KEY array is full */
+	/* KH
+	  prterr(6, "LDKEY is too small for this problem.\n"
+	  "It is not possible to estimate the value of LDKEY "
+	  "required,\n"
+	  "but twice the current value may be sufficient.");
+	  */
+	prterr(6, "LDKEY is too small for this problem.\n"
+	       "Try increasing the size of the workspace.");
+
+
+L30: /* Update KEY */
+
+	key[itp] = *kval;
+	++(*itop);
+	ipoin[itp] = *itop;
+	/* Return if STP array full */
+	if (*itop > *ldstp) {
+	    /* KH
+	       prterr(7, "LDSTP is too small for this problem.\n"
+	       "It is not possible to estimate the value of LDSTP "
+	       "required,\n"
+	       "but twice the current value may be sufficient.");
+	       */
+	    prterr(7, "LDSTP is too small for this problem.\n"
+		   "Try increasing the size of the workspace.");
+	}
+	/* Update STP, etc. */
+	npoin[*itop] = -1;
+	nr   [*itop] = -1;
+	nl   [*itop] = -1;
+	stp  [*itop] = *pastp;
+	ifrq [*itop] = *ifreq;
+	return;
+    }
+
+L40: /* Find location, if any, of pastp */
+
+    ipn = ipoin[itp];
+    test1 = *pastp - *tol;
+    test2 = *pastp + *tol;
+
+    do {
+	if (stp[ipn] < test1)
+	    ipn = nl[ipn];
+	else if (stp[ipn] > test2)
+	    ipn = nr[ipn];
+	else {
+	    ifrq[ipn] += *ifreq;
+	    return;
+	}
+    } while (ipn > 0);
+
+    /* Return if STP array full */
+    ++(*itop);
+    if (*itop > *ldstp) {
+	/*
+	  prterr(7, "LDSTP is too small for this problem.\n"
+	  "It is not possible to estimate the value of LDSTP "
+	  "required,\n"
+	  "but twice the current value may be sufficient.");
+	  */
+	prterr(7, "LDSTP is too small for this problem.\n"
+	       "Try increasing the size of the workspace.");
+	return;
+    }
+
+    /* Find location to add value */
+    ipn = ipoin[itp];
+    itmp = ipn;
+
+L60:
+    if (stp[ipn] < test1) {
+	itmp = ipn;
+	ipn = nl[ipn];
+	if (ipn > 0)
+	    goto L60;
+	/* else */
+	nl[itmp] = *itop;
+    }
+    else if (stp[ipn] > test2) {
+	itmp = ipn;
+	ipn = nr[ipn];
+	if (ipn > 0)
+	    goto L60;
+	/* else */
+	nr[itmp] = *itop;
+    }
+    /* Update STP, etc. */
+    npoin[*itop] = npoin[itmp];
+    npoin[itmp] = *itop;
+    stp	 [*itop] = *pastp;
+    ifrq [*itop] = *ifreq;
+    nl	 [*itop] = -1;
+    nr	 [*itop] = -1;
+}
+
+
+Rboolean
+f6xact(int nrow, int *irow, int *kyy, int *key, int *ldkey, int *last, int *ipn)
+{
+/*
+  -----------------------------------------------------------------------
+  Name:	      F6XACT  aka "GET"
+  Purpose:    Pop a node off the stack.
+
+  Arguments:
+    NROW    - The number of rows in the table.			(Input)
+    IROW    - Vector of length nrow containing the row sums on
+	      output.						(Output)
+    KYY     - Constant mutlipliers used in forming the hash
+	      table key.					(Input)
+    KEY     - Vector of length LDKEY containing the hash table
+	      keys.						(In/out)
+    LDKEY   - Length of vector KEY.				(Input)
+    LAST    - Index of the last key popped off the stack.	(In/out)
+    IPN     - Pointer to the linked list of past path lengths.	(Output)
+
+  Return value :
+    TRUE if there are no additional nodes to process.           (Output)
+  -----------------------------------------------------------------------
+  */
+    int kval, j;
+
+    --key;
+
+L10:
+    ++(*last);
+    if (*last <= *ldkey) {
+	if (key[*last] < 0)
+	    goto L10;
+
+	/* Get KVAL from the stack */
+	kval = key[*last];
+	key[*last] = -9999;
+	for (j = nrow-1; j > 0; j--) {
+	    irow[j] = kval / kyy[j];
+	    kval -= irow[j] * kyy[j];
+	}
+	irow[0] = kval;
+	*ipn = *last;
+	return FALSE;
+    } else {
+	*last = 0;
+	return TRUE;
+    }
+}
+
+
+void
+f7xact(int nrow, int *imax, int *idif, int *k, int *ks, int *iflag)
+{
+/*
+  -----------------------------------------------------------------------
+  Name:	      F7XACT
+  Purpose:    Generate the new nodes for given marginal totals.
+
+  Arguments:
+    NROW    - The number of rows in the table.			(Input)
+    IMAX    - The row marginal totals.				(Input)
+    IDIF    - The column counts for the new column.		(in/out)
+    K	    - Indicator for the row to decrement.		(in/out)
+    KS	    - Indicator for the row to increment.		(in/out)
+    IFLAG   - Status indicator.					(Output)
+	      If IFLAG is zero, a new table was generated.  For
+	      IFLAG = 1, no additional tables could be generated.
+  -----------------------------------------------------------------------
+  */
+    int i, m, kk, mm;
+
+    /* Parameter adjustments */
+    --idif;
+    --imax;
+
+    /* Function Body */
+    *iflag = 0;
+    /* Find node which can be incremented, ks */
+    if (*ks == 0)
+	do {
+	    ++(*ks);
+	} while (idif[*ks] == imax[*ks]);
+
+    /* Find node to decrement (>ks) */
+    if (idif[*k] > 0 && *k > *ks) {
+	--idif[*k];
+	do {
+	    --(*k);
+	} while(imax[*k] == 0);
+
+	m = *k;
+
+	/* Find node to increment (>=ks) */
+	while (idif[m] >= imax[m]) {
+	    --m;
+	}
+	++idif[m];
+	/* Change ks */
+	if (m == *ks && idif[m] == imax[m])
+	    *ks = *k;
+    }
+    else {
+ Loop:
+	/* Check for finish */
+	for (kk = *k + 1; kk <= nrow; ++kk) {
+	    if (idif[kk] > 0) {
+		goto L70;
+	    }
+	}
+	*iflag = 1;
+	return;
+
+ L70:
+	/* Reallocate counts */
+	mm = 1;
+	for (i = 1; i <= *k; ++i) {
+	    mm += idif[i];
+	    idif[i] = 0;
+	}
+	*k = kk;
+
+	do {
+	    --(*k);
+	    m = imin2(mm, imax[*k]);
+	    idif[*k] = m;
+	    mm -= m;
+	} while (mm > 0 && *k != 1);
+
+	/* Check that all counts reallocated */
+	if (mm > 0) {
+	    if (kk != nrow) {
+		*k = kk;
+		goto Loop;
+	    }
+	    *iflag = 1;
+	    return;
+	}
+	/* Get ks */
+	--idif[kk];
+	*ks = 0;
+	do {
+	    ++(*ks);
+	    if (*ks > *k) {
+		return;
+	    }
+	} while (idif[*ks] >= imax[*ks]);
+    }
+}
+
+
+void f8xact(int *irow, int is, int i1, int izero, int *new)
+{
+/*
+  -----------------------------------------------------------------------
+  Name:	      F8XACT
+  Purpose:    Routine for reducing a vector when there is a zero
+	      element.
+  Arguments:
+     IROW   - Vector containing the row counts.			(Input)
+     IS	    - Indicator.					(Input)
+     I1	    - Indicator.					(Input)
+     IZERO  - Position of the zero.				(Input)
+     NEW    - Vector of new row counts.				(Output)
+  -----------------------------------------------------------------------
+  */
+
+    int i;
+
+    /* Parameter adjustments */
+    --new;
+    --irow;
+
+    /* Function Body */
+    for (i = 1; i < i1; ++i)
+	new[i] = irow[i];
+
+    for (i = i1; i <= izero - 1; ++i) {
+	if (is >= irow[i + 1])
+	    break;
+	new[i] = irow[i + 1];
+    }
+
+    new[i] = is;
+
+    for(;;) {
+	++i;
+	if (i > izero)
+	    return;
+	new[i] = irow[i];
+    }
+}
+
+double f9xact(int n, int ntot, int *ir, double *fact)
+{
+/*
+  -----------------------------------------------------------------------
+  Name:	      F9XACT
+  Purpose:    Computes the log of a multinomial coefficient.
+
+  Arguments:
+     N	    - Length of IR.					(Input)
+     NTOT   - Number for factorial in numerator.		(Input)
+     IR	    - Vector of length N containing the numbers for
+	      the denominator of the factorial.			(Input)
+     FACT   - Table of log factorials.				(Input)
+  Returns:
+	    - The log of the multinomal coefficient.		(Output)
+  -----------------------------------------------------------------------
+  */
+    double d;
+    int k;
+
+    d = fact[ntot];
+    for (k = 0; k < n; k++)
+	d -= fact[ir[k]];
+    return d;
+}
+
+
+Rboolean
+f10act(int nrow, int *irow, int ncol, int *icol, double *val,
+       double *fact, int *nd, int *ne, int *m)
+{
+/*
+  -----------------------------------------------------------------------
+  Name:	    F10ACT
+  Purpose:  Computes the shortest path length for special tables.
+
+  Arguments:
+     NROW   - The number of rows in the table.			(Input)
+     IROW   - Vector of length NROW containing the row totals.	(Input)
+     NCOL   - The number of columns in the table.		(Input)
+     ICO    - Vector of length NCOL containing the column totals.(Input)
+     VAL    - The shortest path.				(Input/Output)
+     FACT   - Vector containing the logarithms of factorials.   (Input)
+     ND	    - Workspace vector of length NROW.			(Input)
+     NE	    - Workspace vector of length NCOL.			(Input)
+     M	    - Workspace vector of length NCOL.			(Input)
+
+  Returns (VAL and):
+     XMIN   - Set to true if shortest path obtained.		(Output)
+  -----------------------------------------------------------------------
+  */
+    /* Local variables */
+    int i, is, ix;
+
+    /* Function Body */
+    for (i = 0; i < nrow - 1; ++i)
+	nd[i] = 0;
+
+    is = icol[0] / nrow;
+    ix = icol[0] - nrow * is;
+    ne[0] = is;
+    m[0] = ix;
+    if (ix != 0)
+	++nd[ix-1];
+
+    for (i = 1; i < ncol; ++i) {
+	ix = icol[i] / nrow;
+	ne[i] = ix;
+	is += ix;
+	ix = icol[i] - nrow * ix;
+	m[i] = ix;
+	if (ix != 0)
+	    ++nd[ix-1];
+    }
+
+    for (i = nrow - 3; i >= 0; --i)
+	nd[i] += nd[i + 1];
+
+    ix = 0;
+    for (i = nrow; i >= 2; --i) {
+	ix += is + nd[nrow - i] - irow[i-1];
+	if (ix < 0)
+	    return FALSE;
+    }
+
+    for (i = 0; i < ncol; ++i) {
+	ix = ne[i];
+	is = m[i];
+	*val +=  is * fact[ix + 1] + (nrow - is) * fact[ix];
+    }
+    return TRUE;
+}
+
+
+void f11act(int *irow, int i1, int i2, int *new)
+{
+/*
+  -----------------------------------------------------------------------
+  Name:	      F11ACT
+  Purpose:    Routine for revising row totals.
+
+  Arguments:
+     IROW   - Vector containing the row totals.	(Input)
+     I1	    - Indicator.			(Input)
+     I2	    - Indicator.			(Input)
+     NEW    - Vector containing the row totals.	(Output)
+  -----------------------------------------------------------------------
+  */
+    int i;
+
+    for (i = 0;  i < (i1 - 1); ++i)	new[i] = irow[i];
+    for (i = i1; i <= i2; ++i)	      new[i-1] = irow[i];
+
+    return;
+}
+
+
+void NORET prterr(int icode, const char *mes)
+{
+/*
+  -----------------------------------------------------------------------
+  Name:	      prterr
+  Purpose:    Print an error message and stop.
+
+  Arguments:
+     icode  - Integer code for the error message.		(Input)
+     mes    - Character string containing the error message.	(Input)
+  -----------------------------------------------------------------------
+  */
+    PROBLEM "FEXACT error %d.\n%s", icode, mes RECOVER(NULL_ENTRY);
+}
+
+int iwork(int iwkmax, int *iwkpt, int number, int itype)
+{
+/*
+  -----------------------------------------------------------------------
+  Name:	      iwork
+  Purpose:    Routine for allocating workspace.
+
+  Arguments:
+     iwkmax - Maximum (int) amount of workspace.		(Input)
+     iwkpt  - Amount of (int) workspace currently allocated.	(in/out)
+     number - Number of elements of workspace desired.		(Input)
+     itype  - Workspace type.					(Input)
+	      ITYPE  TYPE
+		2    integer
+		3    float
+		4    double
+     iwork(): Index in rwrk, dwrk, or iwrk of the beginning of
+	      the first free element in the workspace array.	(Output)
+  -----------------------------------------------------------------------
+  */
+    int i;
+
+    i = *iwkpt;
+    if (itype == 2 || itype == 3)
+	*iwkpt += number;
+    else { /* double */
+	if (i % 2 != 0)
+	    ++i;
+	*iwkpt += (number << 1);
+	i /= 2;
+    }
+    if (*iwkpt > iwkmax)
+	prterr(40, "Out of workspace.");
+
+    return i;
+}
+
+
+
+#ifndef USING_R
+
+void isort(int *n, int *ix)
+{
+/*
+  -----------------------------------------------------------------------
+  Name:	      ISORT
+  Purpose:    Shell sort for an int vector.
+
+  Arguments:
+     N	    - Lenth of vector IX.	(Input)
+     IX	    - Vector to be sorted.	(in/out)
+  -----------------------------------------------------------------------
+  */
+    static int ikey, i, j, m, il[10], kl, it, iu[10], ku;
+
+    /* Parameter adjustments */
+    --ix;
+
+    /* Function Body */
+    m = 1;
+    i = 1;
+    j = *n;
+
+L10:
+    if (i >= j) {
+	goto L40;
+    }
+    kl = i;
+    ku = j;
+    ikey = i;
+    ++j;
+    /* Find element in first half */
+L20:
+    ++i;
+    if (i < j) {
+	if (ix[ikey] > ix[i]) {
+	    goto L20;
+	}
+    }
+    /* Find element in second half */
+L30:
+    --j;
+    if (ix[j] > ix[ikey]) {
+	goto L30;
+    }
+    /* Interchange */
+    if (i < j) {
+	it = ix[i];
+	ix[i] = ix[j];
+	ix[j] = it;
+	goto L20;
+    }
+    it = ix[ikey];
+    ix[ikey] = ix[j];
+    ix[j] = it;
+    /* Save upper and lower subscripts of the array yet to be sorted */
+    if (m < 11) {
+	if (j - kl < ku - j) {
+	    il[m - 1] = j + 1;
+	    iu[m - 1] = ku;
+	    i = kl;
+	    --j;
+	} else {
+	    il[m - 1] = kl;
+	    iu[m - 1] = j - 1;
+	    i = j + 1;
+	    j = ku;
+	}
+	++m;
+	goto L10;
+    } else {
+	prterr(20, "This should never occur.");
+    }
+    /* Use another segment */
+L40:
+    --m;
+    if (m == 0) {
+	return;
+    }
+    i = il[m - 1];
+    j = iu[m - 1];
+    goto L10;
+}
+
+double gammds(double *y, double *p, int *ifault)
+{
+/*
+  -----------------------------------------------------------------------
+  Name:	      GAMMDS
+  Purpose:    Cumulative distribution for the gamma distribution.
+  Usage:      PGAMMA (Q, ALPHA,IFAULT)
+  Arguments:
+     Q	    - Value at which the distribution is desired.  (Input)
+     ALPHA  - Parameter in the gamma distribution.  (Input)
+     IFAULT - Error indicator.	(Output)
+	       IFAULT  DEFINITION
+		 0     No error
+		 1     An argument is misspecified.
+		 2     A numerical error has occurred.
+     PGAMMA - The cdf for the gamma distribution with parameter alpha
+	      evaluated at Q.  (Output)
+  -----------------------------------------------------------------------
+
+  Algorithm AS 147 APPL. Statist. (1980) VOL. 29, P. 113
+
+  Computes the incomplete gamma integral for positive parameters Y, P
+  using and infinite series.
+  */
+
+    static double a, c, f, g;
+    static int ifail;
+
+    /* Checks for the admissibility of arguments and value of F */
+    *ifault = 1;
+    g = 0.;
+    if (*y <= 0. || *p <= 0.) {
+	return g;
+    }
+    *ifault = 2;
+
+    /*
+      ALOGAM is natural log of gamma function no need to test ifail as
+      an error is impossible
+      */
+
+    a = *p + 1.;
+    f = exp(*p * log(*y) - alogam(&a, &ifail) - *y);
+    if (f == 0.) {
+	return g;
+    }
+    *ifault = 0;
+
+    /* Series begins */
+    c = 1.;
+    g = 1.;
+    a = *p;
+L10:
+    do {
+	a += 1.;
+	c *= (*y / a);
+	g += c;
+    } while (c > 1e-6 * g);
+
+    g *= f;
+    return g;
+}
+
+/*
+  -----------------------------------------------------------------------
+  Name:	      ALOGAM
+  Purpose:    Value of the log-gamma function.
+  Usage:      ALOGAM (X, IFAULT)
+  Arguments:
+     X	    - Value at which the log-gamma function is to be evaluated.
+	      (Input)
+     IFAULT  - Error indicator.	 (Output)
+	       IFAULT  DEFINITION
+		 0     No error
+		 1     X < 0
+     ALGAMA - The value of the log-gamma function at XX.  (Output)
+  -----------------------------------------------------------------------
+
+  Algorithm ACM 291, Comm. ACM. (1966) Vol. 9, P. 684
+
+  Evaluates natural logarithm of gamma(x) for X greater than zero.
+  */
+
+double alogam(double *x, int *ifault)
+{
+    /* Initialized data */
+
+    static double a1 = .918938533204673;
+    static double a2 = 5.95238095238e-4;
+    static double a3 = 7.93650793651e-4;
+    static double a4 = .002777777777778;
+    static double a5 = .083333333333333;
+
+    /* Local variables */
+    static double f, y, z;
+
+    *ifault = 1;
+    if (*x < 0.) {
+	return(0.);
+    }
+    *ifault = 0;
+    y = *x;
+    f = 0.;
+    if (y >= 7.) {
+	goto L30;
+    }
+    f = y;
+L10:
+    y += 1.;
+    if (y >= 7.) {
+	goto L20;
+    }
+    f *= y;
+    goto L10;
+L20:
+    f = -log(f);
+L30:
+    z = 1. / (y * y);
+    return(f + (y - .5) * log(y) - y + a1 +
+	   (((-a2 * z + a3) * z - a4) * z + a5) / y);
+}
+
+#endif /* not USING_R */
+
+#include <Rinternals.h>
+
+SEXP Fexact(SEXP x, SEXP pars, SEXP work, SEXP smult)
+{
+    int nr = nrows(x), nc = ncols(x), ws = asInteger(work),
+	mult = asInteger(smult);
+    pars = PROTECT(coerceVector(pars, REALSXP));
+    double p, prt, *rp =  REAL(pars);
+    fexact(&nr, &nc, INTEGER(x), &nr, rp, rp+1, rp+2, &prt, &p, &ws, &mult);
+    UNPROTECT(1);
+    return ScalarReal(p);
+}
diff --git a/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/filter.c b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/filter.c
new file mode 100644
index 0000000000000000000000000000000000000000..47214b341bfe35cabc61e88a0080a58875d38200
--- /dev/null
+++ b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/filter.c
@@ -0,0 +1,156 @@
+/*
+ *  R : A Computer Language for Statistical Data Analysis
+
+ *  Copyright (C) 1999-2016   The R Core Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, a copy is available at
+ *  https://www.R-project.org/Licenses/.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <R.h>
+#include "ts.h"
+
+#ifndef min
+#define min(a, b) ((a < b)?(a):(b))
+#define max(a, b) ((a < b)?(b):(a))
+#endif
+
+// currently ISNAN includes NAs
+#define my_isok(x) (!ISNA(x) & !ISNAN(x))
+
+SEXP cfilter(SEXP sx, SEXP sfilter, SEXP ssides, SEXP scircular)
+{
+   if (TYPEOF(sx) != REALSXP || TYPEOF(sfilter) != REALSXP)
+       error("invalid input");
+    R_xlen_t nx = XLENGTH(sx), nf = XLENGTH(sfilter);
+    int sides = asInteger(ssides), circular = asLogical(scircular);
+    if(sides == NA_INTEGER || circular == NA_LOGICAL)  error("invalid input");
+
+    SEXP ans = allocVector(REALSXP, nx);
+
+    R_xlen_t i, j, nshift;
+    double z, tmp, *x = REAL(sx), *filter = REAL(sfilter), *out = REAL(ans);
+
+    if(sides == 2) nshift = nf /2; else nshift = 0;
+    if(!circular) {
+	for(i = 0; i < nx; i++) {
+	    z = 0;
+	    if(i + nshift - (nf - 1) < 0 || i + nshift >= nx) {
+		out[i] = NA_REAL;
+		continue;
+	    }
+	    for(j = max(0, nshift + i - nx); j < min(nf, i + nshift + 1) ; j++) {
+		tmp = x[i + nshift - j];
+		if(my_isok(tmp)) z += filter[j] * tmp;
+		else { out[i] = NA_REAL; goto bad; }
+	    }
+	    out[i] = z;
+	bad:
+	    continue;
+	}
+    } else { /* circular */
+	for(i = 0; i < nx; i++)
+	{
+	    z = 0;
+	    for(j = 0; j < nf; j++) {
+		R_xlen_t ii = i + nshift - j;
+		if(ii < 0) ii += nx;
+		if(ii >= nx) ii -= nx;
+		tmp = x[ii];
+		if(my_isok(tmp)) z += filter[j] * tmp;
+		else { out[i] = NA_REAL; goto bad2; }
+	    }
+	    out[i] = z;
+	bad2:
+	    continue;
+	}
+    }
+    return ans;
+}
+
+/* recursive filtering */
+SEXP rfilter(SEXP x, SEXP filter, SEXP out)
+{
+   if (TYPEOF(x) != REALSXP || TYPEOF(filter) != REALSXP
+       || TYPEOF(out) != REALSXP) error("invalid input");
+    R_xlen_t nx = XLENGTH(x), nf = XLENGTH(filter);
+    double sum, tmp, *r = REAL(out), *rx = REAL(x), *rf = REAL(filter);
+
+    for(R_xlen_t i = 0; i < nx; i++) {
+	sum = rx[i];
+	for (R_xlen_t j = 0; j < nf; j++) {
+	    tmp = r[nf + i - j - 1];
+	    if(my_isok(tmp)) sum += tmp * rf[j];
+	    else { r[nf + i] = NA_REAL; goto bad3; }
+	}
+	r[nf + i] = sum;
+    bad3:
+	continue;
+    }
+    return out;
+}
+
+/* now allows missing values */
+static void
+acf0(double *x, int n, int ns, int nl, Rboolean correlation, double *acf)
+{
+    int d1 = nl+1, d2 = ns*d1;
+
+    for(int u = 0; u < ns; u++)
+	for(int v = 0; v < ns; v++)
+	    for(int lag = 0; lag <= nl; lag++) {
+		double sum = 0.0; int nu = 0;
+		for(int i = 0; i < n-lag; i++)
+		    if(!ISNAN(x[i + lag + n*u]) && !ISNAN(x[i + n*v])) {
+			nu++;
+			sum += x[i + lag + n*u] * x[i + n*v];
+		    }
+		acf[lag + d1*u + d2*v] = (nu > 0) ? sum/(nu + lag) : NA_REAL;
+	    }
+    if(correlation) {
+	if(n == 1) {
+	    for(int u = 0; u < ns; u++)
+		acf[0 + d1*u + d2*u] = 1.0;
+	} else {
+	    double *se = (double *) R_alloc(ns, sizeof(double));
+	    for(int u = 0; u < ns; u++)
+		se[u] = sqrt(acf[0 + d1*u + d2*u]);
+	    for(int u = 0; u < ns; u++)
+		for(int v = 0; v < ns; v++)
+		    for(int lag = 0; lag <= nl; lag++) { // ensure correlations remain in  [-1,1] :
+			double a = acf[lag + d1*u + d2*v] / (se[u]*se[v]);
+			acf[lag + d1*u + d2*v] = (a > 1.) ? 1. : ((a < -1.) ? -1. : a);
+		    }
+	}
+    }
+}
+
+SEXP acf(SEXP x, SEXP lmax, SEXP sCor)
+{
+    int nx = nrows(x), ns = ncols(x), lagmax = asInteger(lmax),
+	cor = asLogical(sCor);
+    x = PROTECT(coerceVector(x, REALSXP));
+    SEXP ans = PROTECT(allocVector(REALSXP, (lagmax + 1)*ns*ns));
+    acf0(REAL(x), nx, ns, lagmax, cor, REAL(ans));
+    SEXP d = PROTECT(allocVector(INTSXP, 3));
+    INTEGER(d)[0] = lagmax + 1;
+    INTEGER(d)[1] = INTEGER(d)[2] = ns;
+    setAttrib(ans, R_DimSymbol, d);
+    UNPROTECT(3);
+    return ans;
+}
diff --git a/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/kendall.c b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/kendall.c
new file mode 100644
index 0000000000000000000000000000000000000000..b80da5a5bb20f003741ea906b5755e75d6c5e49e
--- /dev/null
+++ b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/kendall.c
@@ -0,0 +1,110 @@
+/*
+ *  R : A Computer Language for Statistical Data Analysis
+ *  Copyright (C) 1999-2016   The R Core Team.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, a copy is available at
+ *  https://www.R-project.org/Licenses/
+ */
+
+/* Kendall's rank correlation tau and its exact distribution in case of no ties
+*/
+
+#include <string.h>
+#include <R.h>
+#include <math.h> // for floor
+#include <Rmath.h>
+
+/*
+   and the exact distribution of  T = (n * (n - 1) * tau + 1) / 4,
+   which is -- if there are no ties -- the number of concordant ordered pairs
+*/
+
+static double
+ckendall(int k, int n, double **w) 
+{
+    int i, u;
+    double s;
+
+    u =  (n * (n - 1) / 2);
+    if ((k < 0) || (k > u)) return(0);
+    if (w[n] == 0) {
+	w[n] = (double *) R_alloc(u + 1, sizeof(double));
+	memset(w[n], '\0', sizeof(double) * (u+1));
+	for (i = 0; i <= u; i++) w[n][i] = -1;
+    }
+    if (w[n][k] < 0) {
+	if (n == 1)
+	    w[n][k] = (k == 0);
+	else {
+	    s = 0;
+	    for (i = 0; i < n; i++)
+		s += ckendall(k - i, n - 1, w);
+	    w[n][k] = s;
+	}
+    }
+    return(w[n][k]);
+}
+
+#if 0
+void
+dkendall(int *len, double *x, int *n) 
+{
+    int i;
+    double **w;
+
+    w = (double **) R_alloc(*n + 1, sizeof(double *));
+
+    for (i = 0; i < *len; i++)
+	if (fabs(x[i] - floor(x[i] + 0.5)) > 1e-7) {
+	    x[i] = 0;
+	} else {
+	    x[i] = ckendall((int)x[i], *n) / gammafn(*n + 1, w);
+	}
+}
+#endif
+
+static void
+pkendall(int len, double *Q, double *P, int n) 
+{
+    int i, j;
+    double p, q;
+    double **w;
+
+    w = (double **) R_alloc(n + 1, sizeof(double *));
+    memset(w, '\0', sizeof(double*) * (n+1));
+
+    for (i = 0; i < len; i++) {
+	q = floor(Q[i] + 1e-7);
+	if (q < 0)
+	    P[i] = 0;
+	else if (q > (n * (n - 1) / 2))
+	    P[i] = 1;
+	else {
+	    p = 0;
+	    for (j = 0; j <= q; j++) p += ckendall(j, n, w);
+	    P[i] = p / gammafn(n + 1);
+	}
+    }
+}
+
+#include <Rinternals.h>
+SEXP pKendall(SEXP q, SEXP sn)
+{
+    q = PROTECT(coerceVector(q, REALSXP));
+    int len = LENGTH(q), n = asInteger(sn);
+    SEXP p = PROTECT(allocVector(REALSXP, len));
+    pkendall(len, REAL(q), REAL(p), n);
+    UNPROTECT(2);
+    return p;
+}
diff --git a/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/ks.c b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/ks.c
new file mode 100644
index 0000000000000000000000000000000000000000..2275fcf4da412e95f1e718f81be3f9b7c6aeea83
--- /dev/null
+++ b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/ks.c
@@ -0,0 +1,265 @@
+/*
+ *  R : A Computer Language for Statistical Data Analysis
+ *  Copyright (C) 1999-2016   The R Core Team.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, a copy is available at
+ *  https://www.R-project.org/Licenses/
+ */
+
+/* ks.c
+   Compute the asymptotic distribution of the one- and two-sample
+   two-sided Kolmogorov-Smirnov statistics, and the exact distributions
+   in the two-sided one-sample and two-sample cases.
+*/
+
+#include <math.h>
+#include <R.h>
+#include <Rinternals.h>
+#include <Rmath.h>		/* constants */
+
+static double K(int n, double d);
+static void m_multiply(double *A, double *B, double *C, int m);
+static void m_power(double *A, int eA, double *V, int *eV, int m, int n);
+
+/* Two-sample two-sided asymptotic distribution */
+static void
+pkstwo(int n, double *x, double tol)
+{
+/* x[1:n] is input and output
+ *
+ * Compute
+ *   \sum_{k=-\infty}^\infty (-1)^k e^{-2 k^2 x^2}
+ *   = 1 + 2 \sum_{k=1}^\infty (-1)^k e^{-2 k^2 x^2}
+ *   = \frac{\sqrt{2\pi}}{x} \sum_{k=1}^\infty \exp(-(2k-1)^2\pi^2/(8x^2))
+ *
+ * See e.g. J. Durbin (1973), Distribution Theory for Tests Based on the
+ * Sample Distribution Function.  SIAM.
+ *
+ * The 'standard' series expansion obviously cannot be used close to 0;
+ * we use the alternative series for x < 1, and a rather crude estimate
+ * of the series remainder term in this case, in particular using that
+ * ue^(-lu^2) \le e^(-lu^2 + u) \le e^(-(l-1)u^2 - u^2+u) \le e^(-(l-1))
+ * provided that u and l are >= 1.
+ *
+ * (But note that for reasonable tolerances, one could simply take 0 as
+ * the value for x < 0.2, and use the standard expansion otherwise.)
+ *
+ */
+    double new, old, s, w, z;
+    int i, k, k_max;
+
+    k_max = (int) sqrt(2 - log(tol));
+
+    for(i = 0; i < n; i++) {
+	if(x[i] < 1) {
+	    z = - (M_PI_2 * M_PI_4) / (x[i] * x[i]);
+	    w = log(x[i]);
+	    s = 0;
+	    for(k = 1; k < k_max; k += 2) {
+		s += exp(k * k * z - w);
+	    }
+	    x[i] = s / M_1_SQRT_2PI;
+	}
+	else {
+	    z = -2 * x[i] * x[i];
+	    s = -1;
+	    k = 1;
+	    old = 0;
+	    new = 1;
+	    while(fabs(old - new) > tol) {
+		old = new;
+		new += 2 * s * exp(z * k * k);
+		s *= -1;
+		k++;
+	    }
+	    x[i] = new;
+	}
+    }
+}
+
+/* Two-sided two-sample */
+static double psmirnov2x(double *x, int m, int n)
+{
+    double md, nd, q, *u, w;
+    int i, j;
+
+    if(m > n) {
+	i = n; n = m; m = i;
+    }
+    md = (double) m;
+    nd = (double) n;
+    /*
+       q has 0.5/mn added to ensure that rounding error doesn't
+       turn an equality into an inequality, eg abs(1/2-4/5)>3/10 
+
+    */
+    q = (0.5 + floor(*x * md * nd - 1e-7)) / (md * nd);
+    u = (double *) R_alloc(n + 1, sizeof(double));
+
+    for(j = 0; j <= n; j++) {
+	u[j] = ((j / nd) > q) ? 0 : 1;
+    }
+    for(i = 1; i <= m; i++) {
+	w = (double)(i) / ((double)(i + n));
+	if((i / md) > q)
+	    u[0] = 0;
+	else
+	    u[0] = w * u[0];
+	for(j = 1; j <= n; j++) {
+	    if(fabs(i / md - j / nd) > q) 
+		u[j] = 0;
+	    else
+		u[j] = w * u[j] + u[j - 1];
+	}
+    }
+    return u[n];
+}
+
+static double
+K(int n, double d)
+{
+    /* Compute Kolmogorov's distribution.
+       Code published in
+	 George Marsaglia and Wai Wan Tsang and Jingbo Wang (2003),
+	 "Evaluating Kolmogorov's distribution".
+	 Journal of Statistical Software, Volume 8, 2003, Issue 18.
+	 URL: http://www.jstatsoft.org/v08/i18/.
+    */
+
+   int k, m, i, j, g, eH, eQ;
+   double h, s, *H, *Q;
+
+   /* 
+      The faster right-tail approximation is omitted here.
+      s = d*d*n; 
+      if(s > 7.24 || (s > 3.76 && n > 99)) 
+          return 1-2*exp(-(2.000071+.331/sqrt(n)+1.409/n)*s);
+   */
+   k = (int) (n * d) + 1;
+   m = 2 * k - 1;
+   h = k - n * d;
+   H = (double*) Calloc(m * m, double);
+   Q = (double*) Calloc(m * m, double);
+   for(i = 0; i < m; i++)
+       for(j = 0; j < m; j++)
+	   if(i - j + 1 < 0)
+	       H[i * m + j] = 0;
+	   else
+	       H[i * m + j] = 1;
+   for(i = 0; i < m; i++) {
+       H[i * m] -= R_pow_di(h, i + 1);
+       H[(m - 1) * m + i] -= R_pow_di(h, (m - i));
+   }
+   H[(m - 1) * m] += ((2 * h - 1 > 0) ? R_pow_di(2 * h - 1, m) : 0);
+   for(i = 0; i < m; i++)
+       for(j = 0; j < m; j++)
+	   if(i - j + 1 > 0)
+	       for(g = 1; g <= i - j + 1; g++)
+		   H[i * m + j] /= g;
+   eH = 0;
+   m_power(H, eH, Q, &eQ, m, n);
+   s = Q[(k - 1) * m + k - 1];
+   for(i = 1; i <= n; i++) {
+       s = s * i / n;
+       if(s < 1e-140) {
+	   s *= 1e140;
+	   eQ -= 140;
+       }
+   }
+   s *= R_pow_di(10.0, eQ);
+   Free(H);
+   Free(Q);
+   return(s);
+}
+
+static void
+m_multiply(double *A, double *B, double *C, int m)
+{
+    /* Auxiliary routine used by K().
+       Matrix multiplication.
+    */
+    int i, j, k;
+    double s;
+    for(i = 0; i < m; i++)
+	for(j = 0; j < m; j++) {
+	    s = 0.;
+	    for(k = 0; k < m; k++)
+		s+= A[i * m + k] * B[k * m + j];
+	    C[i * m + j] = s;
+	}
+}
+
+static void
+m_power(double *A, int eA, double *V, int *eV, int m, int n)
+{
+    /* Auxiliary routine used by K().
+       Matrix power.
+    */
+    double *B;
+    int eB , i;
+
+    if(n == 1) {
+	for(i = 0; i < m * m; i++)
+	    V[i] = A[i];
+	*eV = eA;
+	return;
+    }
+    m_power(A, eA, V, eV, m, n / 2);
+    B = (double*) Calloc(m * m, double);
+    m_multiply(V, V, B, m);
+    eB = 2 * (*eV);
+    if((n % 2) == 0) {
+	for(i = 0; i < m * m; i++)
+	    V[i] = B[i];
+	*eV = eB;
+    }
+    else {
+	m_multiply(A, B, V, m);
+	*eV = eA + eB;
+    }
+    if(V[(m / 2) * m + (m / 2)] > 1e140) {
+	for(i = 0; i < m * m; i++)
+	    V[i] = V[i] * 1e-140;
+	*eV += 140;
+    }
+    Free(B);
+}
+
+/* Two-sided two-sample */
+SEXP pSmirnov2x(SEXP statistic, SEXP snx, SEXP sny)
+{
+    int nx = asInteger(snx), ny = asInteger(sny);
+    double st = asReal(statistic);
+    return ScalarReal(psmirnov2x(&st, nx, ny));
+}
+
+/* Two-sample two-sided asymptotic distribution */
+SEXP pKS2(SEXP statistic, SEXP stol)
+{
+    int n = LENGTH(statistic);
+    double tol = asReal(stol);
+    SEXP ans = duplicate(statistic);
+    pkstwo(n, REAL(ans), tol);
+    return ans;
+}
+
+
+/* The two-sided one-sample 'exact' distribution */
+SEXP pKolmogorov2x(SEXP statistic, SEXP sn)
+{
+    int n = asInteger(sn);
+    double st = asReal(statistic), p;
+    p = K(n, st);
+    return ScalarReal(p);
+}
diff --git a/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/ksmooth.c b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/ksmooth.c
new file mode 100644
index 0000000000000000000000000000000000000000..e832c3d88a20c7841b3f84234f23d0cdeee58da9
--- /dev/null
+++ b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/ksmooth.c
@@ -0,0 +1,109 @@
+/*
+ *  R : A Computer Language for Statistical Data Analysis
+ *  Copyright (C) 1998-2016	The R Foundation
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, a copy is available at
+ *  https://www.R-project.org/Licenses/
+ */
+
+#include <math.h>
+#include <R.h>			/* for NA_REAL, includes math.h */
+#include <Rinternals.h>
+
+#ifdef ENABLE_NLS
+#include <libintl.h>
+#define _(String) dgettext ("stats", String)
+#else
+#define _(String) (String)
+#endif
+
+static double dokern(double x, int kern)
+{
+    if(kern == 1) return(1.0);
+    if(kern == 2) return(exp(-0.5*x*x));
+    return(0.0); /* -Wall */
+}
+
+static void BDRksmooth(double *x, double *y, R_xlen_t n,
+		       double *xp, double *yp, R_xlen_t np,
+		       int kern, double bw)
+{
+    R_xlen_t imin = 0;
+    double cutoff = 0.0, num, den, x0, w;
+
+    /* bandwidth is in units of half inter-quartile range. */
+    if(kern == 1) {bw *= 0.5; cutoff = bw;}
+    if(kern == 2) {bw *= 0.3706506; cutoff = 4*bw;}
+    while(x[imin] < xp[0] - cutoff && imin < n) imin++;
+    for(R_xlen_t j = 0; j < np; j++) {
+	num = den = 0.0;
+	x0 = xp[j];
+	for(R_xlen_t i = imin; i < n; i++) {
+	    if(x[i] < x0 - cutoff) imin = i;
+	    else {
+		if(x[i] > x0 + cutoff) break;
+		w = dokern(fabs(x[i] - x0)/bw, kern);
+		num += w*y[i];
+		den += w;
+	    }
+	}
+	if(den > 0) yp[j] = num/den; else yp[j] = NA_REAL;
+    }
+}
+
+
+// called only from  spline()  in ./ppr.f
+void NORET F77_SUB(bdrsplerr)(void)
+{
+    error(_("only 2500 rows are allowed for sm.method=\"spline\""));
+}
+
+void F77_SUB(splineprt)(double* df, double* gcvpen, int* ismethod,
+			      double* lambda, double *edf)
+{
+    Rprintf("spline(df=%5.3g, g.pen=%11.6g, ismeth.=%+2d) -> (lambda, edf) = (%.7g, %5.2f)\n",
+	    *df, *gcvpen, *ismethod, *lambda, *edf);
+    return;
+}
+
+// called only from smooth(..., trace=TRUE)  in ./ppr.f :
+void F77_SUB(smoothprt)(double* span, int* iper, double* var, double* cvar)
+{
+    Rprintf("smooth(span=%4g, iper=%+2d) -> (var, cvar) = (%g, %g)\n",
+	    *span, *iper, *var, *cvar);
+    return;
+}
+
+
+SEXP ksmooth(SEXP x, SEXP y, SEXP xp, SEXP skrn, SEXP sbw)
+{
+    int krn = asInteger(skrn);
+    double bw = asReal(sbw);
+    x = PROTECT(coerceVector(x, REALSXP));
+    y = PROTECT(coerceVector(y, REALSXP));
+    xp = PROTECT(coerceVector(xp, REALSXP));
+    R_xlen_t nx = XLENGTH(x), np = XLENGTH(xp);
+    SEXP yp = PROTECT(allocVector(REALSXP, np));
+
+    BDRksmooth(REAL(x), REAL(y), nx, REAL(xp), REAL(yp), np, krn, bw);
+    SEXP ans = PROTECT(allocVector(VECSXP, 2));
+    SET_VECTOR_ELT(ans, 0, xp);
+    SET_VECTOR_ELT(ans, 1, yp);
+    SEXP nm = allocVector(STRSXP, 2);
+    setAttrib(ans, R_NamesSymbol, nm);
+    SET_STRING_ELT(nm, 0, mkChar("x"));
+    SET_STRING_ELT(nm, 1, mkChar("y"));
+    UNPROTECT(5);
+    return ans;
+}
diff --git a/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/line.c b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/line.c
new file mode 100644
index 0000000000000000000000000000000000000000..b912a078248ad064be0eeb3e98dd35840359a9ed
--- /dev/null
+++ b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/line.c
@@ -0,0 +1,133 @@
+/*
+ *  R : A Computer Language for Statistical Data Analysis
+ *  Copyright (C) 1997-2016   The R Core Team.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, a copy is available at
+ *  https://www.R-project.org/Licenses/
+ */
+
+#include <R_ext/Utils.h>	/* R_rsort() */
+#include <math.h>
+
+#include <Rinternals.h>
+#include "statsR.h"
+
+/* Speed up by `inlining' these (as macros) [since R version 1.2] : */
+#if 1
+#define il(n,x)	(int)floor((n - 1) * x)
+#define iu(n,x)	(int) ceil((n - 1) * x)
+
+#else
+static int il(int n, double x)
+{
+    return (int)floor((n - 1) * x) ;
+}
+
+static int iu(int n, double x)
+{
+    return (int)ceil((n - 1) * x);
+}
+#endif
+
+static void line(double *x, double *y, /* input (x[i],y[i])s */
+		 double *z, double *w, /* work and output: resid. & fitted */
+		 /* all the above of length */ int n,
+		 double coef[2])
+{
+    int i, j, k;
+    double xb, x1, x2, xt, yt, yb, tmp1, tmp2;
+    double slope, yint;
+
+    for(i = 0 ; i < n ; i++) {
+	z[i] = x[i];
+	w[i] = y[i];
+    }
+    R_rsort(z, n);/* z = ordered abscissae */
+
+    tmp1 = z[il(n, 1./6.)];
+    tmp2 = z[iu(n, 1./6.)];	xb = 0.5*(tmp1+tmp2);
+
+    tmp1 = z[il(n, 2./6.)];
+    tmp2 = z[iu(n, 2./6.)];	x1 = 0.5*(tmp1+tmp2);
+
+    tmp1 = z[il(n, 4./6.)];
+    tmp2 = z[iu(n, 4./6.)];	x2 = 0.5*(tmp1+tmp2);
+
+    tmp1 = z[il(n, 5./6.)];
+    tmp2 = z[iu(n, 5./6.)];	xt = 0.5*(tmp1+tmp2);
+
+    slope = 0.;
+
+    for(j = 1 ; j <= 1 ; j++) {
+	/* yb := Median(y[i]; x[i] <= quantile(x, 1/3) */
+	k = 0;
+	for(i = 0 ; i < n ; i++)
+	    if(x[i] <= x1)
+		z[k++] = w[i];
+	R_rsort(z, k);
+	yb = 0.5 * (z[il(k, 0.5)] + z[iu(k, 0.5)]);
+
+	/* yt := Median(y[i]; x[i] >= quantile(x, 2/3) */
+	k = 0;
+	for(i = 0 ; i < n ; i++)
+	    if(x[i] >= x2)
+		z[k++] = w[i];
+	R_rsort(z,k);
+	yt = 0.5 * (z[il(k, 0.5)] + z[iu(k, 0.5)]);
+
+	slope += (yt - yb)/(xt - xb);
+	for(i = 0 ; i < n ; i++) {
+	    z[i] = y[i] - slope*x[i];
+	    /* never used: w[i] = z[i]; */
+	}
+	R_rsort(z,n);
+	yint = 0.5 * (z[il(n, 0.5)] + z[iu(n, 0.5)]);
+    }
+    for( i = 0 ; i < n ; i++ ) {
+	w[i] = yint + slope*x[i];
+	z[i] = y[i] - w[i];
+    }
+    coef[0] = yint;
+    coef[1] = slope;
+}
+
+void tukeyline0(double *x, double *y, double *z, double *w, int *n,
+	       double *coef)
+{
+    line(x, y, z, w, *n, coef);
+}
+
+SEXP tukeyline(SEXP x, SEXP y, SEXP call)
+{
+    int n = LENGTH(x);
+    if (n < 2) error("insufficient observations");
+    SEXP ans;
+    ans = PROTECT(allocVector(VECSXP, 4));
+    SEXP nm = allocVector(STRSXP, 4);
+    setAttrib(ans, R_NamesSymbol, nm);
+    SET_STRING_ELT(nm, 0, mkChar("call"));
+    SET_STRING_ELT(nm, 1, mkChar("coefficients"));
+    SET_STRING_ELT(nm, 2, mkChar("residuals"));
+    SET_STRING_ELT(nm, 3, mkChar("fitted.values"));
+    SET_VECTOR_ELT(ans, 0, call);
+    SEXP coef = allocVector(REALSXP, 2);
+    SET_VECTOR_ELT(ans, 1, coef);
+    SEXP res = allocVector(REALSXP, n);
+    SET_VECTOR_ELT(ans, 2, res);
+    SEXP fit = allocVector(REALSXP, n);
+    SET_VECTOR_ELT(ans, 3, fit);
+    line(REAL(x), REAL(y), REAL(res), REAL(fit), n, REAL(coef));
+    UNPROTECT(1);
+    return ans;
+}
diff --git a/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/loglin.c b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/loglin.c
new file mode 100644
index 0000000000000000000000000000000000000000..dd04cc8cbf218d10250657d659fdc4d33516c0b5
--- /dev/null
+++ b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/loglin.c
@@ -0,0 +1,392 @@
+/* Algorithm AS 51 Appl. Statist. (1972), vol. 21, p. 218
+   original (C) Royal Statistical Society 1972
+
+   Performs an iterative proportional fit of the marginal totals of a
+   contingency table.
+*/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <math.h>
+
+#include <stdio.h>
+#include <R_ext/Memory.h>
+#include <R_ext/Applic.h>
+
+#undef max
+#undef min
+#undef abs
+#define	max(a, b)		((a) < (b) ? (b) : (a))
+#define	min(a, b)		((a) > (b) ? (b) : (a))
+#define	abs(x)			((x) >= 0 ? (x) : -(x))
+
+static void collap(int nvar, double *x, double *y, int locy,
+		   int *dim, int *config);
+static void adjust(int nvar, double *x, double *y, double *z,
+		   int *locz, int *dim, int *config, double *d);
+
+/* Table of constant values */
+
+static void 
+loglin(int nvar, int *dim, int ncon, int *config, int ntab,
+       double *table, double *fit, int *locmar, int nmar, double *marg,
+       int nu, double *u, double maxdev, int maxit,
+       double *dev, int *nlast, int *ifault)
+{
+    // nvar could be zero (no-segfault test)
+    if (!nvar) error("no variables");  // not translated
+    int i, j, k, n, point, size, check[nvar], icon[nvar];
+    double x, y, xmax;
+
+    /* Parameter adjustments */
+    --dim;
+    --locmar;
+    config -= nvar + 1;
+    --fit;
+    --table;
+    --marg;
+    --u;
+    --dev;
+
+    /* Function body */
+
+    *ifault = 0;
+    *nlast = 0;
+
+    /* Check validity of NVAR, the number of variables, and of maxit,
+       the maximum number of iterations */
+
+    if (nvar > 0 && maxit > 0) goto L10;
+L5:
+    *ifault = 4;
+    return;
+
+    /* Look at table and fit constants */
+
+L10:
+    size = 1;
+    for (j = 1; j <= nvar; j++) {
+	if (dim[j] <= 0) goto L5;
+	size *= dim[j];
+    }
+    if (size <= ntab) goto L40;
+L35:
+    *ifault = 2;
+    return;
+L40:
+    x = 0.;
+    y = 0.;
+    for (i = 1; i <= size; i++) {
+	if (table[i] < 0. || fit[i] < 0.) goto L5;
+	x += table[i];
+	y += fit[i];
+    }
+
+    /* Make a preliminary adjustment to obtain the fit to an empty
+       configuration list */
+
+    if (y == 0.) goto L5;
+    x /= y;
+    for (i = 1; i <= size; i++) fit[i] = x * fit[i];
+    if (ncon <= 0 || config[nvar + 1] == 0) return;
+
+    /* Allocate marginal tables */
+
+    point = 1;
+    for (i = 1; i <= ncon; i++) {
+	/* A zero beginning a configuration indicates that the list is
+	   completed */
+	if (config[i * nvar + 1] == 0)  goto L160;
+	/* Get marginal table size.  While doing this task, see if the
+	   configuration list contains duplications or elements out of
+	   range. */
+	size = 1;
+	for (j = 0; j < nvar; j++) check[j] = 0;
+	for (j = 1; j <= nvar; j++) {
+	    k = config[j + i * nvar];
+	    /* A zero indicates the end of the string. */
+	    if (k == 0) goto L130;
+	    /* See if element is valid. */
+	    if (k >= 0 && k <= nvar) goto L100;
+L95:
+	    *ifault = 1;
+	    return;
+	    /* Check for duplication */
+L100:
+	    if (check[k - 1]) goto L95;
+	    check[k - 1] = 1;
+	    /* Get size */
+	    size *= dim[k];
+	}
+
+	/* Since U is used to store fitted marginals, size must not
+	   exceed NU */
+L130:
+	if (size > nu) goto L35;
+
+	/* LOCMAR points to marginal tables to be placed in MARG */
+	locmar[i] = point;
+	point += size;
+    }
+
+    /* Get N, number of valid configurations */
+
+    i = ncon + 1;
+L160:
+    n = i - 1;
+
+    /* See if MARG can hold all marginal tables */
+
+    if (point > nmar + 1) goto L35;
+
+    /* Obtain marginal tables */
+
+    for (i = 1; i <= n; i++) {
+	for (j = 1; j <= nvar; j++) {
+	    icon[j - 1] = config[j + i * nvar];
+	}
+	collap(nvar, &table[1], &marg[1], locmar[i], &dim[1], icon);
+    }
+
+    /* Perform iterations */
+
+    for (k = 1; k <= maxit; k++) {
+	/* XMAX is maximum deviation observed between fitted and true
+	   marginal during a cycle */
+	xmax = 0.;
+	for (i = 1; i <= n; i++) {
+	    for (j = 1; j <= nvar; j++) icon[j - 1] = config[j + i * nvar];
+	    collap(nvar, &fit[1], &u[1], 1, &dim[1], icon);
+	    adjust(nvar, &fit[1], &u[1], &marg[1], &locmar[i], &dim[1], icon, &xmax);
+	}
+	/* Test convergence */
+	dev[k] = xmax;
+	if (xmax < maxdev) goto L240;
+    }
+    if (maxit > 1) goto L230;
+    *nlast = 1;
+    return;
+
+    /* No convergence */
+L230:
+    *ifault = 3;
+    *nlast = maxit;
+    return;
+
+    /* Normal termination */
+L240:
+    *nlast = k;
+
+    return;
+}
+
+/* Algorithm AS 51.1 Appl. Statist. (1972), vol. 21, p. 218
+
+   Computes a marginal table from a complete table.
+   All parameters are assumed valid without test.
+
+   The larger table is X and the smaller one is Y.
+*/
+
+void collap(int nvar, double *x, double *y, int locy, int *dim, int *config)
+{
+    int i, j, k, l, n, locu, size[nvar + 1], coord[nvar];
+
+    /* Parameter adjustments */
+    --config;
+    --dim;
+    --x;
+    --y;
+
+    /* Initialize arrays */
+
+    size[0] = 1;
+    for (k = 1; k <= nvar; k++) {
+	l = config[k];
+	if (l == 0)  goto L20;
+	size[k] = size[k - 1] * dim[l];
+    }
+
+    /* Find number of variables in configuration */
+
+    k = nvar + 1;
+L20:
+    n = k - 1;
+
+    /* Initialize Y.  First cell of marginal table is at Y(LOCY) and
+       table has SIZE(K) elements */
+
+    locu = locy + size[k - 1] - 1;
+    for (j = locy; j <= locu; j++) y[j] = 0.;
+
+    /* Initialize coordinates */
+
+    for (k = 0; k < nvar; k++) coord[k] = 0;
+
+    /* Find locations in tables */
+    i = 1;
+L60:
+    j = locy;
+    for (k = 1; k <= n; k++) {
+	l = config[k];
+	j += coord[l - 1] * size[k - 1];
+    }
+    y[j] += x[i];
+
+    /* Update coordinates */
+
+    i++;
+    for (k = 1; k <= nvar; k++) {
+	coord[k - 1]++;
+	if (coord[k - 1] < dim[k]) goto L60;
+	coord[k - 1] = 0;
+    }
+
+    return;
+}
+
+
+/* Algorithm AS 51.2 Appl. Statist. (1972), vol. 21, p. 218
+
+   Makes proportional adjustment corresponding to CONFIG.
+   All parameters are assumed valid without test.
+   */
+
+void adjust(int nvar, double *x, double *y, double *z, int *locz,
+	   int *dim, int *config, double *d)
+{
+    int i, j, k, l, n, size[nvar + 1], coord[nvar];
+    double e;
+
+    /* Parameter adjustments */
+    --config;
+    --dim;
+    --x;
+    --y;
+    --z;
+
+    /* Set size array */
+
+    size[0] = 1;
+    for (k = 1; k <= nvar; k++) {
+	l = config[k];
+	if (l == 0) goto L20;
+	size[k] = size[k - 1] * dim[l];
+    }
+
+    /* Find number of variables in configuration */
+
+    k = nvar + 1;
+L20:
+    n = k - 1;
+
+    /* Test size of deviation */
+
+    l = size[k - 1];
+    j = 1;
+    k = *locz;
+    for (i = 1; i <= l; i++) {
+	e = abs(z[k] - y[j]);
+	if (e > *d) {
+	    *d = e;
+	}
+	j++;
+	k++;
+    }
+
+    /* Initialize coordinates */
+
+    for (k = 0; k < nvar; k++)  coord[k] = 0;
+    i = 1;
+
+    /* Perform adjustment */
+
+L50:
+    j = 0;
+    for (k = 1; k <= n; k++) {
+	l = config[k];
+	j += coord[l - 1] * size[k - 1];
+    }
+    k = j + *locz;
+    j++;
+
+    /* Note that Y(J) should be non-negative */
+
+    if (y[j] <= 0.) x[i] = 0.;
+    if (y[j] > 0.) x[i] = x[i] * z[k] / y[j];
+
+    /* Update coordinates */
+
+    i++;
+    for (k = 1; k <= nvar; k++) {
+	coord[k - 1]++;
+	if (coord[k - 1] < dim[k]) goto L50;
+	coord[k - 1] = 0;
+    }
+
+    return;
+}
+
+#undef max
+#undef min
+#undef abs
+
+#include <R.h>
+#include <Rinternals.h>
+#include "statsR.h"
+#ifdef ENABLE_NLS
+#include <libintl.h>
+#define _(String) dgettext ("stats", String)
+#else
+#define _(String) (String)
+#endif
+
+SEXP LogLin(SEXP dtab, SEXP conf, SEXP table, SEXP start, 
+	    SEXP snmar, SEXP eps, SEXP iter) 
+{
+    int nvar = length(dtab), 
+	ncon = ncols(conf), 
+	ntab = length(table),
+	nmar = asInteger(snmar), 
+	maxit = asInteger(iter), 
+	nlast, ifault;
+    double maxdev = asReal(eps);
+    SEXP fit = PROTECT(TYPEOF(start) == REALSXP ? duplicate(start) :
+		       coerceVector(start, REALSXP)),
+	locmar = PROTECT(allocVector(INTSXP, ncon)),
+	marg = PROTECT(allocVector(REALSXP, nmar)),
+	u = PROTECT(allocVector(REALSXP, ntab)),
+	dev = PROTECT(allocVector(REALSXP, maxit));
+    dtab = PROTECT(coerceVector(dtab, INTSXP));
+    conf = PROTECT(coerceVector(conf, INTSXP));
+    table = PROTECT(coerceVector(table, REALSXP));
+    loglin(nvar, INTEGER(dtab), ncon, INTEGER(conf), ntab,
+	   REAL(table), REAL(fit), INTEGER(locmar), nmar, REAL(marg),
+	   ntab, REAL(u), maxdev, maxit, REAL(dev), &nlast, &ifault);
+    switch(ifault) {
+    case 1:
+    case 2:
+	error(_("this should not happen")); break;
+    case 3:
+	warning(_("algorithm did not converge")); break;
+    case 4:
+	error(_("incorrect specification of 'table' or 'start'")); break;
+    default: 
+	break;
+    }
+
+    SEXP ans = PROTECT(allocVector(VECSXP, 3)), nm;
+    SET_VECTOR_ELT(ans, 0, fit);
+    SET_VECTOR_ELT(ans, 1, dev);
+    SET_VECTOR_ELT(ans, 2, ScalarInteger(nlast));
+    nm = allocVector(STRSXP, 3);
+    setAttrib(ans, R_NamesSymbol, nm);
+    SET_STRING_ELT(nm, 0, mkChar("fit"));
+    SET_STRING_ELT(nm, 1, mkChar("dev"));
+    SET_STRING_ELT(nm, 2, mkChar("nlast"));
+    UNPROTECT(9);
+    return ans;
+}
+
diff --git a/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/lowess.c b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/lowess.c
new file mode 100644
index 0000000000000000000000000000000000000000..bbacab7884343a7eec37b860fc3f8e19f19d2c66
--- /dev/null
+++ b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/lowess.c
@@ -0,0 +1,306 @@
+/*
+ *  R : A Computer Langage for Statistical Data Analysis
+ *  Copyright (C) 1996  Robert Gentleman and Ross Ihaka
+ *  Copyright (C) 1999-2016 The R Core Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, a copy is available at
+ *  https://www.R-project.org/Licenses/
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef ENABLE_NLS
+#include <libintl.h>
+#define _(String) dgettext ("stats", String)
+#else
+#define _(String) (String)
+#endif
+
+#include <math.h>
+#include <Rmath.h>		/* fmax2, imin2, imax2 */
+#include <R_ext/Applic.h>	/* prototypes for lowess and clowess */
+#include <R_ext/Boolean.h>
+#include <R_ext/Utils.h>	/* rPsort() */
+#ifdef DEBUG_lowess
+# include <R_ext/Print.h>
+#endif
+
+static R_INLINE double fsquare(double x)
+{
+    return x * x;
+}
+
+static R_INLINE double fcube(double x)
+{
+    return x * x * x;
+}
+
+static void lowest(double *x, double *y, int n, double *xs, double *ys,
+	int nleft, int nright, double *w,
+	Rboolean userw, double *rw, Rboolean *ok)
+{
+    int nrt, j;
+    double a, b, c, h, h1, h9, r, range;
+
+    x--;
+    y--;
+    w--;
+    rw--;
+
+    range = x[n]-x[1];
+    h = fmax2(*xs-x[nleft], x[nright]-*xs);
+    h9 = 0.999*h;
+    h1 = 0.001*h;
+
+    /* sum of weights */
+
+    a = 0.;
+    j = nleft;
+    while (j <= n) {
+
+	/* compute weights */
+	/* (pick up all ties on right) */
+
+	w[j] = 0.;
+	r = fabs(x[j] - *xs);
+	if (r <= h9) {
+	    if (r <= h1)
+		w[j] = 1.;
+	    else
+		w[j] = fcube(1.-fcube(r/h));
+	    if (userw)
+		w[j] *= rw[j];
+	    a += w[j];
+	}
+	else if (x[j] > *xs)
+	    break;
+	j = j+1;
+    }
+
+    /* rightmost pt (may be greater */
+    /* than nright because of ties) */
+
+    nrt = j-1;
+    if (a <= 0.)
+	*ok = FALSE;
+    else {
+	*ok = TRUE;
+
+	/* weighted least squares */
+	/* make sum of w[j] == 1 */
+
+	for(j=nleft ; j<=nrt ; j++)
+	    w[j] /= a;
+	if (h > 0.) {
+	    a = 0.;
+
+	    /*  use linear fit */
+	    /* weighted center of x values */
+
+	    for(j=nleft ; j<=nrt ; j++)
+		a += w[j] * x[j];
+	    b = *xs - a;
+	    c = 0.;
+	    for(j=nleft ; j<=nrt ; j++)
+		c += w[j]*fsquare(x[j]-a);
+	    if (sqrt(c) > 0.001*range) {
+		b /= c;
+
+		/* points are spread out */
+		/* enough to compute slope */
+
+		for(j=nleft; j <= nrt; j++)
+		    w[j] *= (b*(x[j]-a) + 1.);
+	    }
+	}
+	*ys = 0.;
+	for(j=nleft; j <= nrt; j++)
+	    *ys += w[j] * y[j];
+    }
+}
+
+static
+void clowess(double *x, double *y, int n,
+	     double f, int nsteps, double delta,
+	     double *ys, double *rw, double *res)
+{
+    int i, iter, j, last, m1, m2, nleft, nright, ns;
+    Rboolean ok;
+    double alpha, c1, c9, cmad, cut, d1, d2, denom, r, sc;
+
+    if (n < 2) {
+	ys[0] = y[0]; return;
+    }
+
+    /* nleft, nright, last, etc. must all be shifted to get rid of these: */
+    x--;
+    y--;
+    ys--;
+
+
+    /* at least two, at most n points */
+    ns = imax2(2, imin2(n, (int)(f*n + 1e-7)));
+#ifdef DEBUG_lowess
+    REprintf("lowess(): ns = %d\n", ns);
+#endif
+
+    /* robustness iterations */
+
+    iter = 1;
+    while (iter <= nsteps+1) {
+	nleft = 1;
+	nright = ns;
+	last = 0;	/* index of prev estimated point */
+	i = 1;		/* index of current point */
+
+	for(;;) {
+	    if (nright < n) {
+
+		/* move nleft,  nright to right */
+		/* if radius decreases */
+
+		d1 = x[i] - x[nleft];
+		d2 = x[nright+1] - x[i];
+
+		/* if d1 <= d2 with */
+		/* x[nright+1] == x[nright], */
+		/* lowest fixes */
+
+		if (d1 > d2) {
+
+		    /* radius will not */
+		    /* decrease by */
+		    /* move right */
+
+		    nleft++;
+		    nright++;
+		    continue;
+		}
+	    }
+
+	    /* fitted value at x[i] */
+
+	    lowest(&x[1], &y[1], n, &x[i], &ys[i],
+		   nleft, nright, res, iter>1, rw, &ok);
+	    if (!ok) ys[i] = y[i];
+
+	    /* all weights zero */
+	    /* copy over value (all rw==0) */
+
+	    if (last < i-1) {
+		denom = x[i]-x[last];
+
+		/* skipped points -- interpolate */
+		/* non-zero - proof? */
+
+		for(j = last+1; j < i; j++) {
+		    alpha = (x[j]-x[last])/denom;
+		    ys[j] = alpha*ys[i] + (1.-alpha)*ys[last];
+		}
+	    }
+
+	    /* last point actually estimated */
+	    last = i;
+
+	    /* x coord of close points */
+	    cut = x[last]+delta;
+	    for (i = last+1; i <= n; i++) {
+		if (x[i] > cut)
+		    break;
+		if (x[i] == x[last]) {
+		    ys[i] = ys[last];
+		    last = i;
+		}
+	    }
+	    i = imax2(last+1, i-1);
+	    if (last >= n)
+		break;
+	}
+	/* residuals */
+	for(i = 0; i < n; i++)
+	    res[i] = y[i+1] - ys[i+1];
+
+	/* overall scale estimate */
+	sc = 0.;
+	for(i = 0; i < n; i++) sc += fabs(res[i]);
+	sc /= n;
+
+	/* compute robustness weights */
+	/* except last time */
+
+	if (iter > nsteps)
+	    break;
+	/* Note: The following code, biweight_{6 MAD|Ri|}
+	   is also used in stl(), loess and several other places.
+	   --> should provide API here (MM) */
+	for(i = 0 ; i < n ; i++)
+	    rw[i] = fabs(res[i]);
+
+	/* Compute   cmad := 6 * median(rw[], n)  ---- */
+	/* FIXME: We need C API in R for Median ! */
+	m1 = n/2;
+	/* partial sort, for m1 & m2 */
+	rPsort(rw, n, m1);
+	if(n % 2 == 0) {
+	    m2 = n-m1-1;
+	    rPsort(rw, n, m2);
+	    cmad = 3.*(rw[m1]+rw[m2]);
+	}
+	else { /* n odd */
+	    cmad = 6.*rw[m1];
+	}
+#ifdef DEBUG_lowess
+	REprintf("   cmad = %12g\n", cmad);
+#endif
+	if(cmad < 1e-7 * sc) /* effectively zero */
+	    break;
+	c9 = 0.999*cmad;
+	c1 = 0.001*cmad;
+	for(i = 0 ; i < n ; i++) {
+	    r = fabs(res[i]);
+	    if (r <= c1)
+		rw[i] = 1.;
+	    else if (r <= c9)
+		rw[i] = fsquare(1.-fsquare(r/cmad));
+	    else
+		rw[i] = 0.;
+	}
+	iter++;
+    }
+}
+
+#include <Rinternals.h>
+SEXP lowess(SEXP x, SEXP y, SEXP sf, SEXP siter, SEXP sdelta)
+{
+    if(TYPEOF(x) != REALSXP || TYPEOF(y) != REALSXP) error("invalid input");
+    int nx = LENGTH(x);
+    if (nx == NA_INTEGER || nx == 0) error("invalid input");
+    double f = asReal(sf);
+    if (!R_FINITE(f) || f <= 0) error(_("'f' must be finite and > 0"));
+    int iter = asInteger(siter);
+    if (iter == NA_INTEGER || iter < 0) 
+	error(_("'iter' must be finite and >= 0"));
+    double delta = asReal(sdelta), *rw, *res;
+    if (!R_FINITE(delta) || delta < 0) 
+	error(_("'delta' must be finite and > 0"));
+    SEXP ans;
+    PROTECT(ans = allocVector(REALSXP, nx));
+    rw = (double *) R_alloc(nx, sizeof(double));
+    res = (double *) R_alloc(nx, sizeof(double));
+    clowess(REAL(x), REAL(y), nx, f, iter, delta, REAL(ans), rw, res);
+    UNPROTECT(1);
+    return ans;
+}
diff --git a/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/mAR.c b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/mAR.c
new file mode 100644
index 0000000000000000000000000000000000000000..a995f8f89a5c534b7c3396122ab872c79636ed9b
--- /dev/null
+++ b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/mAR.c
@@ -0,0 +1,994 @@
+/*
+ *  Copyright (C) 1999 Martyn Plummer
+ *  Copyright (C) 1999-2016 The R Core Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, a copy is available at
+ *  https://www.R-project.org/Licenses/.
+ */
+
+#include <math.h>
+#include <string.h>
+#include <R.h>
+#include <R_ext/Applic.h>	/* Fortran routines */
+#include "ts.h"
+#include "stats.h"
+
+
+#define MAX_DIM_LENGTH 4
+
+#define VECTOR(x) (x.vec)
+#define MATRIX(x) (x.mat)
+#define ARRAY1(x) (x.vec)
+#define ARRAY2(x) (x.mat)
+#define ARRAY3(x) (x.arr3)
+#define ARRAY4(x) (x.arr4)
+#define DIM(x)    (x.dim)
+#define NROW(x)   (x.dim[0])
+#define NCOL(x)   (x.dim[1])
+#define DIM_LENGTH(x) (x.ndim)
+
+
+typedef struct array {
+    double *vec;
+    double **mat;
+    double ***arr3;
+    double ****arr4;
+    int dim[MAX_DIM_LENGTH];
+    int ndim;
+} Array;
+
+static Array make_array(double vec[], int dim[], int ndim);
+static Array make_zero_array(int dim[], int ndim);
+static Array make_matrix(double vec[], int nrow, int ncol);
+static Array make_zero_matrix(int nrow, int ncol);
+static Array make_identity_matrix(int n);
+
+static Array subarray(Array a, int index);
+
+static int vector_length(Array a);
+
+static void set_array_to_zero(Array arr);
+static void copy_array (Array orig, Array ans);
+static void array_op(Array arr1, Array arr2, char op, Array ans);
+static void scalar_op(Array arr, double s, char op, Array ans);
+
+static void transpose_matrix(Array mat, Array ans);
+static void matrix_prod(Array mat1, Array mat2, int trans1, int trans2,
+			Array ans);
+
+
+/* Functions for dynamically allocating arrays
+
+   The Array structure contains pointers to arrays which are allocated
+   using the R_alloc function.	Although the .C() interface cleans up
+   all memory assigned with R_alloc, judicious use of vmaxget() vmaxset()
+   to free this memory is probably wise. See memory.c in R core.
+
+*/
+
+static void assert(int bool)
+{
+    if(!bool)
+	error(("assert failed in src/library/ts/src/carray.c"));
+}
+
+static Array init_array(void)
+{
+    int i;
+    Array a;
+
+    /* Initialize everything to zero.  Useful for debugging */
+    ARRAY1(a) = (double *) '\0';
+    ARRAY2(a) = (double **) '\0';
+    ARRAY3(a) = (double ***) '\0';
+    ARRAY4(a) = (double ****) '\0';
+    for (i = 0; i < MAX_DIM_LENGTH; i++)
+	DIM(a)[i] = 0;
+    DIM_LENGTH(a) = 0;
+
+    return a;
+}
+
+static int vector_length(Array a)
+{
+    int i, len;
+
+    for (i = 0, len = 1; i < DIM_LENGTH(a); i++) {
+	len *= DIM(a)[i];
+    }
+
+    return len;
+}
+
+
+static Array make_array(double vec[], int dim[], int ndim)
+{
+    int d, i, j;
+    int len[MAX_DIM_LENGTH + 1];
+    Array a;
+
+    assert(ndim <= MAX_DIM_LENGTH);
+
+    a = init_array();
+
+    len[ndim] = 1;
+    for (d = ndim; d >= 1; d--) {
+	len[d-1] = len[d] * dim[ndim - d];
+    }
+
+    for (d = 1; d <= ndim; d++) {
+       switch(d) {
+	   case 1:
+	       VECTOR(a) = vec;
+	       break;
+	   case 2:
+	       ARRAY2(a) = (double**) R_alloc(len[2 - 1],sizeof(double*));
+	       for(i = 0, j = 0; i < len[2 - 1]; i++, j+=dim[ndim - 2 + 1]) {
+		  ARRAY2(a)[i] = ARRAY1(a) + j;
+	       }
+	       break;
+	   case 3:
+	       ARRAY3(a) = (double***) R_alloc(len[3 - 1],sizeof(double**));
+	       for(i = 0, j = 0; i < len[3 - 1]; i++, j+=dim[ndim - 3 + 1]) {
+		  ARRAY3(a)[i] = ARRAY2(a) + j;
+	       }
+	       break;
+	   case 4:
+	       ARRAY4(a) = (double****) R_alloc(len[4 - 1],sizeof(double***));
+	       for(i = 0, j = 0; i < len[4 - 1]; i++, j+=dim[ndim - 4 + 1]) {
+		  ARRAY4(a)[i] = ARRAY3(a) + j;
+	       }
+	       break;
+	   default:
+	       break;
+       }
+    }
+
+    for (i = 0; i < ndim; i++) {
+       DIM(a)[i] = dim[i];
+    }
+    DIM_LENGTH(a) = ndim;
+
+    return a;
+}
+
+static Array make_zero_array(int dim[], int ndim)
+{
+    int i;
+    int len;
+    double *vec;
+
+    for (i = 0, len = 1; i < ndim; i++) {
+	len *= dim[i];
+    }
+
+    vec = (double *) R_alloc(len, sizeof(double));
+    for (i = 0; i < len; i++) {
+	vec[i] = 0.0;
+    }
+
+    return make_array(vec, dim, ndim);
+
+}
+
+static Array make_matrix(double vec[], int nrow, int ncol)
+{
+   int dim[2];
+
+   dim[0] = nrow;
+   dim[1] = ncol;
+   return make_array(vec, dim, 2);
+}
+
+static Array make_zero_matrix(int nrow, int ncol)
+{
+   int dim[2];
+   Array a;
+
+   dim[0] = nrow;
+   dim[1] = ncol;
+   a = make_zero_array(dim, 2);
+   return a;
+}
+
+static Array subarray(Array a, int index)
+/* Return subarray of array a in the form of an Array
+   structure so it can be manipulated by other functions
+   NB The data are not copied, so any changes made to the
+      subarray will affect the original array.
+*/
+{
+    int i, offset;
+    Array b;
+
+    b = init_array();
+
+    /* is index in range? */
+    assert( index >= 0 && index < DIM(a)[0] );
+
+    offset = index;
+    switch(DIM_LENGTH(a)) {
+    /* NB Falling through here */
+	case 4:
+	    offset *= DIM(a)[DIM_LENGTH(a) - 4 + 1];
+	    ARRAY3(b) = ARRAY3(a) + offset;
+	case 3:
+	    offset *= DIM(a)[DIM_LENGTH(a) - 3 + 1];
+	    ARRAY2(b) = ARRAY2(a) + offset;
+	case 2:
+	    offset *= DIM(a)[DIM_LENGTH(a) - 2 + 1];
+	    ARRAY1(b) = ARRAY1(a) + offset;
+	    break;
+	default:
+	    break;
+    }
+
+
+    DIM_LENGTH(b) = DIM_LENGTH(a) - 1;
+
+    for (i = 0; i < DIM_LENGTH(b); i++)
+	DIM(b)[i] = DIM(a)[i+1];
+
+    return b;
+
+}
+
+static int test_array_conform(Array a1, Array a2)
+{
+   int i, ans = FALSE;
+
+   if (DIM_LENGTH(a1) != DIM_LENGTH(a2))
+      return FALSE;
+   else
+      for (i = 0; i < DIM_LENGTH(a1); i++) {
+	 if (DIM(a1)[i] == DIM(a2)[i])
+	    ans = TRUE;
+	 else
+	    return FALSE;
+      }
+
+   return ans;
+}
+
+static void copy_array (Array orig, Array ans)
+/* copy matrix orig to ans */
+{
+    int i;
+
+    assert (test_array_conform(orig, ans));
+
+    for(i = 0; i < vector_length(orig); i++)
+	VECTOR(ans)[i] = VECTOR(orig)[i];
+}
+
+static void transpose_matrix(Array mat, Array ans)
+{
+    int i,j;
+    const void *vmax;
+    Array tmp;
+
+    tmp = init_array();
+
+    assert(DIM_LENGTH(mat) == 2 && DIM_LENGTH(ans) == 2);
+    assert(NCOL(mat) == NROW(ans));
+    assert(NROW(mat) == NCOL(ans));
+
+    vmax = vmaxget();
+
+    tmp = make_zero_matrix(NROW(ans), NCOL(ans));
+    for(i = 0; i < NROW(mat); i++)
+	for(j = 0; j < NCOL(mat); j++)
+	   MATRIX(tmp)[j][i] = MATRIX(mat)[i][j];
+    copy_array(tmp, ans);
+
+    vmaxset(vmax);
+}
+
+static void array_op(Array arr1, Array arr2, char op, Array ans)
+/* Element-wise array operations */
+{
+    int i;
+
+    assert (test_array_conform(arr1, arr2));
+    assert (test_array_conform(arr2, ans));
+
+    switch (op) {
+	case '*':
+	    for (i = 0; i < vector_length(ans); i++)
+		VECTOR(ans)[i] = VECTOR(arr1)[i] * VECTOR(arr2)[i];
+	    break;
+	case '+':
+	    for (i = 0; i < vector_length(ans); i++)
+		VECTOR(ans)[i] = VECTOR(arr1)[i] + VECTOR(arr2)[i];
+	    break;
+	case '/':
+	    for (i = 0; i < vector_length(ans); i++)
+		VECTOR(ans)[i] = VECTOR(arr1)[i] / VECTOR(arr2)[i];
+	    break;
+	case '-':
+	    for (i = 0; i < vector_length(ans); i++)
+		VECTOR(ans)[i] = VECTOR(arr1)[i] - VECTOR(arr2)[i];
+	    break;
+	default:
+	    printf("Unknown op in array_op");
+    }
+}
+
+
+static void scalar_op(Array arr, double s, char op, Array ans)
+/* Elementwise scalar operations */
+{
+    int i;
+
+    assert (test_array_conform(arr, ans));
+
+    switch (op) {
+	case '*':
+	    for (i = 0; i < vector_length(ans); i++)
+		VECTOR(ans)[i] = VECTOR(arr)[i] * s;
+	    break;
+	case '+':
+	    for (i = 0; i < vector_length(ans); i++)
+		VECTOR(ans)[i] = VECTOR(arr)[i] + s;
+	    break;
+	case '/':
+	    for (i = 0; i < vector_length(ans); i++)
+		VECTOR(ans)[i] = VECTOR(arr)[i] / s;
+	    break;
+	case '-':
+	    for (i = 0; i < vector_length(ans); i++)
+		VECTOR(ans)[i] = VECTOR(arr)[i] - s;
+	    break;
+	default:
+	    printf("Unknown op in array_op");
+    }
+}
+
+static void matrix_prod(Array mat1, Array mat2, int trans1, int trans2, Array ans)
+/*
+    General matrix product between mat1 and mat2. Put answer in ans.
+    trans1 and trans2 are logical flags which indicate if the matrix is
+    to be transposed. Normal matrix multiplication has trans1 = trans2 = 0.
+*/
+{
+    int i,j,k,K1,K2;
+    const void *vmax;
+    double m1, m2;
+    Array tmp;
+
+    /* Test whether everything is a matrix */
+    assert(DIM_LENGTH(mat1) == 2 &&
+	   DIM_LENGTH(mat2) == 2 && DIM_LENGTH(ans) == 2);
+
+    /* Test whether matrices conform. K is the dimension that is
+       lost by multiplication */
+    if (trans1) {
+	assert ( NCOL(mat1) == NROW(ans) );
+	K1 = NROW(mat1);
+    }
+    else {
+	assert ( NROW(mat1) == NROW(ans) );
+	K1 = NCOL(mat1);
+    }
+    if (trans2) {
+	assert ( NROW(mat2) == NCOL(ans) );
+	K2 = NCOL(mat2);
+    }
+    else {
+	assert ( NCOL(mat2) == NCOL(ans) );
+	K2 = NROW(mat2);
+    }
+    assert (K1 == K2);
+
+    tmp = init_array();
+
+    /* In case ans is the same as mat1 or mat2, we create a temporary
+       matrix to hold the answer, then copy it to ans
+    */
+    vmax = vmaxget();
+
+    tmp = make_zero_matrix(NROW(ans), NCOL(ans));
+    for (i = 0; i < NROW(tmp); i++) {
+	for (j = 0; j < NCOL(tmp); j++) {
+	    for(k = 0; k < K1; k++) {
+		    m1 = (trans1) ? MATRIX(mat1)[k][i] : MATRIX(mat1)[i][k];
+		    m2 = (trans2) ? MATRIX(mat2)[j][k] : MATRIX(mat2)[k][j];
+		    MATRIX(tmp)[i][j] += m1 * m2;
+	    }
+	}
+    }
+    copy_array(tmp, ans);
+
+    vmaxset(vmax);
+}
+
+static void set_array_to_zero(Array arr)
+{
+    int i;
+
+    for (i = 0; i < vector_length(arr); i++)
+	VECTOR(arr)[i] = 0.0;
+}
+
+static Array make_identity_matrix(int n)
+{
+    int i;
+    Array a;
+
+    a = make_zero_matrix(n,n);
+    for(i = 0; i < n; i++)
+	MATRIX(a)[i][i] = 1.0;
+
+    return a;
+}
+
+static void qr_solve(Array x, Array y, Array coef)
+/* Translation of the R function qr.solve into pure C
+   NB We have to transpose the matrices since the ordering of an array is different in Fortran
+   NB2 We have to copy x to avoid it being overwritten.
+*/
+{
+    int i, info = 0, rank, *pivot, n, p;
+    const void *vmax;
+    double tol = 1.0E-7, *qraux, *work;
+    Array xt, yt, coeft;
+
+    assert(NROW(x) == NROW(y));
+    assert(NCOL(coef) == NCOL(y));
+    assert(NCOL(x) == NROW(coef));
+
+    vmax = vmaxget();
+
+    qraux = (double *) R_alloc(NCOL(x), sizeof(double));
+    pivot = (int *) R_alloc(NCOL(x), sizeof(int));
+    work  = (double *) R_alloc(2*NCOL(x), sizeof(double));
+
+    for(i = 0; i < NCOL(x); i++)
+	pivot[i] = i+1;
+
+    xt = make_zero_matrix(NCOL(x), NROW(x));
+    transpose_matrix(x,xt);
+
+    n = NROW(x);
+    p = NCOL(x);
+
+    F77_CALL(dqrdc2)(VECTOR(xt), &n, &n, &p, &tol, &rank,
+		       qraux, pivot, work);
+
+    if (rank != p)
+	error(_("Singular matrix in qr_solve"));
+
+    yt = make_zero_matrix(NCOL(y), NROW(y));
+    coeft = make_zero_matrix(NCOL(coef), NROW(coef));
+    transpose_matrix(y, yt);
+
+    F77_CALL(dqrcf)(VECTOR(xt), &NROW(x), &rank, qraux,
+	yt.vec, &NCOL(y), coeft.vec, &info);
+
+    transpose_matrix(coeft,coef);
+
+    vmaxset(vmax);
+}
+
+static double ldet(Array x)
+/* Log determinant of square matrix */
+{
+    int i, rank, *pivot, n, p;
+    const void *vmax;
+    double ll, tol = 1.0E-7, *qraux, *work;
+    Array xtmp;
+
+    assert(DIM_LENGTH(x) == 2); /* is x a matrix? */
+    assert(NROW(x) == NCOL(x)); /* is x square? */
+
+    vmax = vmaxget();
+
+    qraux = (double *) R_alloc(NCOL(x), sizeof(double));
+    pivot = (int *) R_alloc(NCOL(x), sizeof(int));
+    work  = (double *) R_alloc(2*NCOL(x), sizeof(double));
+
+    xtmp = make_zero_matrix(NROW(x), NCOL(x));
+    copy_array(x, xtmp);
+
+    for(i = 0; i < NCOL(x); i++)
+	pivot[i] = i+1;
+
+    p = n = NROW(x);
+
+    F77_CALL(dqrdc2)(VECTOR(xtmp), &n, &n, &p, &tol, &rank,
+		       qraux, pivot, work);
+
+    if (rank != p)
+	error(_("Singular matrix in ldet"));
+
+    for (i = 0, ll=0.0; i < rank; i++) {
+	 ll += log(fabs(MATRIX(xtmp)[i][i]));
+    }
+
+    vmaxset(vmax);
+
+    return ll;
+}
+
+
+
+/* Burg's algorithm for autoregression estimation
+
+   multi_burg  is the interface to R. It also handles model selection
+	       using AIC
+
+   burg        implements the main part of the algorithm
+
+   burg2       estimates the partial correlation coefficient. This
+	       requires iteration in the multivariate case.
+
+   Notation
+
+   resid	residuals (forward and backward)
+   A		Estimates of autocorrelation coefficients
+   V		Prediction Variance
+   K		Partial correlation coefficient
+*/
+
+
+#define BURG_MAX_ITER 20
+#define BURG_TOL      1.0E-8
+
+void multi_burg(int *pn, double *x, int *pomax, int *pnser, double *coef,
+    double *pacf, double *var, double *aic, int *porder, int *useaic,
+    int *vmethod);
+static void burg0(int omax, Array resid_f, Array resid_b, Array *A, Array *B,
+    Array P, Array V, int vmethod);
+static void burg2(Array ss_ff, Array ss_bb, Array ss_fb, Array E,
+    Array KA, Array KB);
+
+void multi_burg(int *pn, double *x, int *pomax, int *pnser, double *coef,
+	double *pacf, double *var, double *aic, int *porder, int *useaic,
+	int *vmethod)
+{
+    int i, j, m, omax = *pomax, n = *pn, nser=*pnser, order=*porder;
+    int dim1[3];
+    double aicmin;
+    Array xarr, resid_f, resid_b, resid_f_tmp;
+    Array *A, *B, P, V;
+
+    dim1[0] = omax+1; dim1[1] = dim1[2] = nser;
+    A = (Array *) R_alloc(omax+1, sizeof(Array));
+    B = (Array *) R_alloc(omax+1, sizeof(Array));
+    for (i = 0; i <= omax; i++) {
+	A[i] = make_zero_array(dim1, 3);
+	B[i] = make_zero_array(dim1, 3);
+    }
+    P = make_array(pacf, dim1, 3);
+    V = make_array(var, dim1, 3);
+
+    xarr = make_matrix(x, nser, n);
+    resid_f = make_zero_matrix(nser, n);
+    resid_b = make_zero_matrix(nser, n);
+    set_array_to_zero(resid_b);
+    copy_array(xarr, resid_f);
+    copy_array(xarr, resid_b);
+    resid_f_tmp = make_zero_matrix(nser, n);
+
+    burg0(omax, resid_f, resid_b, A, B, P, V, *vmethod);
+
+    /* Model order selection */
+
+    for (i = 0; i <= omax; i++) {
+	aic[i] = n * ldet(subarray(V,i)) + 2 * i * nser * nser;
+    }
+    if (*useaic) {
+	order = 0;
+	aicmin = aic[0];
+	for (i = 1; i <= omax; i++) {
+	    if (aic[i] < aicmin) {
+		aicmin = aic[i];
+		order = i;
+	    }
+	}
+    }
+    else order = omax;
+    *porder = order;
+
+    for(i = 0; i < vector_length(A[order]); i++)
+	coef[i] = VECTOR(A[order])[i];
+
+    if (*useaic) {
+	/* Recalculate residuals for chosen model */
+	set_array_to_zero(resid_f);
+	set_array_to_zero(resid_f_tmp);
+	for (m = 0; m <= order; m++) {
+	    for (i = 0; i < NROW(resid_f_tmp); i++) {
+		for (j = 0; j < NCOL(resid_f_tmp) - order; j++) {
+		    MATRIX(resid_f_tmp)[i][j + order] = MATRIX(xarr)[i][j + order - m];
+		}
+	    }
+	    matrix_prod(subarray(A[order],m), resid_f_tmp, 0, 0, resid_f_tmp);
+	    array_op(resid_f_tmp, resid_f, '+', resid_f);
+	}
+    }
+    copy_array(resid_f, xarr);
+
+}
+
+
+static void burg0(int omax, Array resid_f, Array resid_b, Array *A, Array *B,
+    Array P, Array V, int vmethod)
+{
+    int i, j, m, n = NCOL(resid_f), nser=NROW(resid_f);
+    Array ss_ff, ss_bb, ss_fb;
+    Array resid_f_tmp, resid_b_tmp;
+    Array KA, KB, E;
+    Array id, tmp;
+
+    ss_ff = make_zero_matrix(nser, nser);
+    ss_fb = make_zero_matrix(nser, nser);
+    ss_bb = make_zero_matrix(nser, nser);
+
+    resid_f_tmp = make_zero_matrix(nser, n);
+    resid_b_tmp = make_zero_matrix(nser, n);
+
+    id    = make_identity_matrix(nser);
+
+    tmp   = make_zero_matrix(nser, nser);
+
+    E = make_zero_matrix(nser, nser);
+    KA = make_zero_matrix(nser, nser);
+    KB = make_zero_matrix(nser, nser);
+
+    set_array_to_zero(A[0]);
+    set_array_to_zero(B[0]);
+    copy_array(id, subarray(A[0],0));
+    copy_array(id, subarray(B[0],0));
+
+    matrix_prod(resid_f, resid_f, 0, 1, E);
+    scalar_op(E, n, '/',  E);
+    copy_array(E, subarray(V,0));
+
+    for (m = 0; m < omax; m++) {
+
+	for(i = 0; i < nser; i++) {
+	    for (j = n - 1; j > m; j--) {
+		MATRIX(resid_b)[i][j] = MATRIX(resid_b)[i][j-1];
+	    }
+	    MATRIX(resid_f)[i][m] = 0.0;
+	    MATRIX(resid_b)[i][m] = 0.0;
+	}
+	matrix_prod(resid_f, resid_f, 0, 1, ss_ff);
+	matrix_prod(resid_b, resid_b, 0, 1, ss_bb);
+	matrix_prod(resid_f, resid_b, 0, 1, ss_fb);
+
+	burg2(ss_ff, ss_bb, ss_fb, E, KA, KB);		/* Update K */
+
+	for (i = 0; i <= m + 1; i++) {
+
+	    matrix_prod(KA, subarray(B[m], m + 1 - i), 0, 0, tmp);
+	    array_op(subarray(A[m], i), tmp, '-', subarray(A[m+1], i));
+
+	    matrix_prod(KB, subarray(A[m], m + 1 - i), 0, 0, tmp);
+	    array_op(subarray(B[m], i), tmp, '-', subarray(B[m+1], i));
+
+	}
+
+	matrix_prod(KA, resid_b, 0, 0, resid_f_tmp);
+	matrix_prod(KB, resid_f, 0, 0, resid_b_tmp);
+	array_op(resid_f, resid_f_tmp, '-', resid_f);
+	array_op(resid_b, resid_b_tmp, '-', resid_b);
+
+	if (vmethod == 1) {
+	    matrix_prod(KA, KB, 0, 0, tmp);
+	    array_op(id, tmp, '-', tmp);
+	    matrix_prod(tmp, E, 0, 0, E);
+	}
+	else if (vmethod == 2) {
+	    matrix_prod(resid_f, resid_f, 0, 1, E);
+	    matrix_prod(resid_b, resid_b, 0, 1, tmp);
+	    array_op(E, tmp, '+', E);
+	    scalar_op(E, 2.0*(n - m - 1), '/', E);
+	}
+	else error(_("Invalid vmethod"));
+
+	copy_array(E, subarray(V,m+1));
+	copy_array(KA, subarray(P,m+1));
+    }
+}
+
+
+static void burg2(Array ss_ff, Array ss_bb, Array ss_fb, Array E,
+   Array KA, Array KB)
+/*
+   Estimate partial correlation by minimizing (1/2)*log(det(s)) where
+   "s" is the the sum of the forward and backward prediction errors.
+
+   In the multivariate case, the forward (KA) and backward (KB) partial
+   correlation coefficients are related by
+
+      KA = solve(E) %*% t(KB) %*% E
+
+   where E is the prediction variance.
+
+*/
+{
+    int i, j, k, l, nser = NROW(ss_ff);
+    int iter;
+    Array ss_bf;
+    Array s, tmp, d1;
+    Array D1, D2, THETA, THETAOLD, THETADIFF, TMP;
+    Array obj;
+    Array e, f, g, h, sg, sh;
+    Array theta;
+
+    ss_bf = make_zero_matrix(nser,nser);
+    transpose_matrix(ss_fb, ss_bf);
+    s = make_zero_matrix(nser, nser);
+    tmp = make_zero_matrix(nser, nser);
+    d1 = make_zero_matrix(nser, nser);
+
+    e = make_zero_matrix(nser, nser);
+    f = make_zero_matrix(nser, nser);
+    g = make_zero_matrix(nser, nser);
+    h = make_zero_matrix(nser, nser);
+    sg = make_zero_matrix(nser, nser);
+    sh = make_zero_matrix(nser, nser);
+
+    theta = make_zero_matrix(nser, nser);
+
+    D1 = make_zero_matrix(nser*nser, 1);
+    D2 = make_zero_matrix(nser*nser, nser*nser);
+    THETA = make_zero_matrix(nser*nser, 1);	/* theta in vector form */
+    THETAOLD = make_zero_matrix(nser*nser, 1);
+    THETADIFF = make_zero_matrix(nser*nser, 1);
+    TMP = make_zero_matrix(nser*nser, 1);
+
+    obj = make_zero_matrix(1,1);
+
+    /* utility matrices e,f,g,h */
+    qr_solve(E, ss_bf, e);
+    qr_solve(E, ss_fb, f);
+    qr_solve(E, ss_bb, tmp);
+    transpose_matrix(tmp, tmp);
+    qr_solve(E, tmp, g);
+    qr_solve(E, ss_ff, tmp);
+    transpose_matrix(tmp, tmp);
+    qr_solve(E, tmp, h);
+
+    for(iter = 0; iter < BURG_MAX_ITER; iter++)
+    {
+	/* Forward and backward partial correlation coefficients */
+	transpose_matrix(theta, tmp);
+	qr_solve(E, tmp, tmp);
+	transpose_matrix(tmp, KA);
+
+	qr_solve(E, theta, tmp);
+	transpose_matrix(tmp, KB);
+
+	/* Sum of forward and backward prediction errors ... */
+	set_array_to_zero(s);
+
+	/* Forward */
+	array_op(s, ss_ff, '+', s);
+	matrix_prod(KA, ss_bf, 0, 0, tmp);
+	array_op(s, tmp, '-', s);
+	transpose_matrix(tmp, tmp);
+	array_op(s, tmp, '-', s);
+	matrix_prod(ss_bb, KA, 0, 1, tmp);
+	matrix_prod(KA, tmp, 0, 0, tmp);
+	array_op(s, tmp, '+', s);
+
+	/* Backward */
+	array_op(s, ss_bb, '+', s);
+	matrix_prod(KB, ss_fb, 0, 0, tmp);
+	array_op(s, tmp, '-', s);
+	transpose_matrix(tmp, tmp);
+	array_op(s, tmp, '-', s);
+	matrix_prod(ss_ff, KB, 0, 1, tmp);
+	matrix_prod(KB, tmp, 0, 0, tmp);
+	array_op(s, tmp, '+', s);
+
+	matrix_prod(s, f, 0, 0, d1);
+	matrix_prod(e, s, 1, 0, tmp);
+	array_op(d1, tmp, '+', d1);
+
+	/*matrix_prod(g,s,0,0,sg);*/
+	matrix_prod(s,g,0,0,sg);
+	matrix_prod(s,h,0,0,sh);
+
+	for (i = 0; i < nser; i++) {
+	    for (j = 0; j < nser; j++) {
+		MATRIX(D1)[nser*i+j][0] = MATRIX(d1)[i][j];
+		for (k = 0; k < nser; k++)
+		    for (l = 0; l < nser; l++) {
+			MATRIX(D2)[nser*i+j][nser*k+l] =
+			    (i == k) * MATRIX(sg)[j][l] +
+			    MATRIX(sh)[i][k] * (j == l);
+		    }
+	    }
+	}
+
+	copy_array(THETA, THETAOLD);
+	qr_solve(D2, D1, THETA);
+
+	for (i = 0; i < vector_length(theta); i++)
+	    VECTOR(theta)[i] = VECTOR(THETA)[i];
+
+	matrix_prod(D2, THETA, 0, 0, TMP);
+
+	array_op(THETAOLD, THETA, '-', THETADIFF);
+	matrix_prod(D2, THETADIFF, 0, 0, TMP);
+	matrix_prod(THETADIFF, TMP, 1, 0, obj);
+	if (VECTOR(obj)[0] < BURG_TOL)
+	    break;
+
+    }
+
+    if (iter == BURG_MAX_ITER)
+	error(_("Burg's algorithm failed to find partial correlation"));
+}
+
+/* Whittle's algorithm for autoregression estimation
+
+   multi_yw  is the interface to R. It also handles model selection using AIC
+
+   whittle,whittle2     implement Whittle's recursion for solving the multivariate
+			Yule-Walker equations.
+
+   Notation
+
+   resid        residuals (forward and backward)
+   A            Estimates of forward autocorrelation coefficients
+   B            Estimates of backward autocorrelation coefficients
+   EA,EB        Prediction Variance
+   KA,KB        Partial correlation coefficient
+*/
+
+void multi_yw(double *acf, int *pn, int *pomax, int *pnser, double *coef,
+	      double *pacf, double *var, double *aic, int *porder,
+	      int *puseaic);
+static void whittle(Array acf, int nlag, Array *A, Array *B, Array p_forward,
+		    Array v_forward, Array p_back, Array v_back);
+static void whittle2 (Array acf, Array Aold, Array Bold, int lag,
+		      char *direction, Array A, Array K, Array E);
+
+
+void multi_yw(double *acf, int *pn, int *pomax, int *pnser, double *coef,
+	      double *pacf, double *var, double *aic, int *porder, int *useaic)
+{
+    int i, m;
+    int  omax = *pomax, n = *pn, nser=*pnser, order=*porder;
+    double aicmin;
+    Array acf_array, p_forward, p_back, v_forward, v_back;
+    Array *A, *B;
+    int dim[3];
+
+    dim[0] = omax+1; dim[1] = dim[2] = nser;
+    acf_array = make_array(acf, dim, 3);
+    p_forward = make_array(pacf, dim, 3);
+    v_forward = make_array(var, dim, 3);
+
+    /* Backward equations (discarded) */
+    p_back= make_zero_array(dim, 3);
+    v_back= make_zero_array(dim, 3);
+
+    A = (Array *) R_alloc(omax+2, sizeof(Array));
+    B = (Array *) R_alloc(omax+2, sizeof(Array));
+    for (i = 0; i <= omax; i++) {
+	A[i] = make_zero_array(dim, 3);
+	B[i] = make_zero_array(dim, 3);
+    }
+    whittle(acf_array, omax, A, B, p_forward, v_forward, p_back, v_back);
+
+    /* Model order selection */
+
+    for (m = 0; m <= omax; m++) {
+	aic[m] = n * ldet(subarray(v_forward,m)) + 2 * m * nser * nser;
+    }
+    if (*useaic) {
+	order = 0;
+	aicmin = aic[0];
+	for (m = 0; m <= omax; m++) {
+	    if (aic[m] < aicmin) {
+		aicmin = aic[m];
+		order = m;
+	    }
+	}
+    }
+    else order = omax;
+    *porder = order;
+
+    for(i = 0; i < vector_length(A[order]); i++)
+	coef[i] = VECTOR(A[order])[i];
+}
+
+static void whittle(Array acf, int nlag, Array *A, Array *B, Array p_forward,
+    Array v_forward, Array p_back, Array v_back)
+{
+
+    int lag, nser = DIM(acf)[1];
+    const void *vmax;
+    Array EA, EB;	/* prediction variance */
+    Array KA, KB;	/* partial correlation coefficient */
+    Array id, tmp;
+
+    vmax = vmaxget();
+
+    KA = make_zero_matrix(nser, nser);
+    EA = make_zero_matrix(nser, nser);
+
+    KB = make_zero_matrix(nser, nser);
+    EB = make_zero_matrix(nser, nser);
+
+    id = make_identity_matrix(nser);
+
+    copy_array(id, subarray(A[0],0));
+    copy_array(id, subarray(B[0],0));
+    copy_array(id, subarray(p_forward,0));
+    copy_array(id, subarray(p_back,0));
+
+    for (lag = 1; lag <= nlag; lag++) {
+
+	whittle2(acf, A[lag-1], B[lag-1], lag, "forward", A[lag], KA, EB);
+	whittle2(acf, B[lag-1], A[lag-1], lag, "back", B[lag], KB, EA);
+
+	copy_array(EA, subarray(v_forward,lag-1));
+	copy_array(EB, subarray(v_back,lag-1));
+
+	copy_array(KA, subarray(p_forward,lag));
+	copy_array(KB, subarray(p_back,lag));
+
+    }
+
+    tmp = make_zero_matrix(nser,nser);
+
+    matrix_prod(KB,KA, 1, 1, tmp);
+    array_op(id, tmp, '-', tmp);
+    matrix_prod(EA, tmp, 0, 0, subarray(v_forward, nlag));
+
+    vmaxset(vmax);
+
+}
+
+static void whittle2 (Array acf, Array Aold, Array Bold, int lag,
+		      char *direction, Array A, Array K, Array E)
+{
+
+    int d, i, nser=DIM(acf)[1];
+    const void *vmax;
+    Array beta, tmp, id;
+
+    d = strcmp(direction, "forward") == 0;
+
+    vmax = vmaxget();
+
+    beta = make_zero_matrix(nser,nser);
+    tmp = make_zero_matrix(nser, nser);
+    id = make_identity_matrix(nser);
+
+    set_array_to_zero(E);
+    copy_array(id, subarray(A,0));
+
+    for(i = 0; i < lag; i++) {
+       matrix_prod(subarray(acf,lag - i), subarray(Aold,i), d, 1, tmp);
+       array_op(beta, tmp, '+', beta);
+       matrix_prod(subarray(acf,i), subarray(Bold,i), d, 1, tmp);
+       array_op(E, tmp, '+', E);
+    }
+    qr_solve(E, beta, K);
+    transpose_matrix(K,K);
+    for (i = 1; i <= lag; i++) {
+	matrix_prod(K, subarray(Bold,lag - i), 0, 0, tmp);
+	array_op(subarray(Aold,i), tmp, '-', subarray(A,i));
+    }
+
+    vmaxset(vmax);
+}
diff --git a/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/pacf.c b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/pacf.c
new file mode 100644
index 0000000000000000000000000000000000000000..6189fdc3b989e7182fc035d8b7976fc8fe0c578e
--- /dev/null
+++ b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/pacf.c
@@ -0,0 +1,477 @@
+/*  R : A Computer Language for Statistical Data Analysis
+ *
+ *  Copyright (C) 1999-2016	The R Core Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, a copy is available at
+ *  https://www.R-project.org/Licenses/.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <R.h>
+#include "ts.h"
+
+#ifndef max
+#define max(a,b) ((a < b)?(b):(a))
+#endif
+#ifndef min
+#define min(a,b) ((a > b)?(b):(a))
+#endif
+
+
+/* Internal */
+static void partrans(int np, double *raw, double *new);
+static void dotrans(Starma G, double *raw, double *new, int trans);
+
+
+/* cor is the autocorrelations starting from 0 lag*/
+static void uni_pacf(double *cor, double *p, int nlag)
+{
+    double a, b, c, *v, *w;
+
+    v = (double*) R_alloc(nlag, sizeof(double));
+    w = (double*) R_alloc(nlag, sizeof(double));
+    w[0] = p[0] = cor[1];
+    for(int ll = 1; ll < nlag; ll++) {
+	a = cor[ll+1];
+	b = 1.0;
+	for(int i = 0; i < ll; i++) {
+	    a -= w[i] * cor[ll - i];
+	    b -= w[i] * cor[i + 1];
+	}
+	p[ll] = c = a/b;
+	if(ll+1 == nlag) break;
+	w[ll] = c;
+	for(int i = 0; i < ll; i++)
+	    v[ll-i-1] = w[i];
+	for(int i = 0; i < ll; i++)
+	    w[i] -= c*v[i];
+    }
+}
+
+SEXP pacf1(SEXP acf, SEXP lmax)
+{
+    int lagmax = asInteger(lmax);
+    acf = PROTECT(coerceVector(acf, REALSXP));
+    SEXP ans = PROTECT(allocVector(REALSXP, lagmax));
+    uni_pacf(REAL(acf), REAL(ans), lagmax);
+    SEXP d = PROTECT(allocVector(INTSXP, 3));
+    INTEGER(d)[0] = lagmax;
+    INTEGER(d)[1] = INTEGER(d)[2] = 1;
+    setAttrib(ans, R_DimSymbol, d);
+    UNPROTECT(3);
+    return ans;
+}
+
+
+/* Use an external reference to store the structure we keep allocated
+   memory in */
+static SEXP Starma_tag;
+
+#define GET_STARMA \
+    Starma G; \
+    if (TYPEOF(pG) != EXTPTRSXP || R_ExternalPtrTag(pG) != Starma_tag) \
+	error(_("bad Starma struct"));\
+    G = (Starma) R_ExternalPtrAddr(pG)
+
+SEXP setup_starma(SEXP na, SEXP x, SEXP pn, SEXP xreg, SEXP pm,
+		  SEXP dt, SEXP ptrans, SEXP sncond)
+{
+    Starma G;
+    int i, n, m, ip, iq, ir, np;
+    SEXP res;
+    double *rx = REAL(x), *rxreg = REAL(xreg);
+
+    G = Calloc(1, starma_struct);
+    G->mp = INTEGER(na)[0];
+    G->mq = INTEGER(na)[1];
+    G->msp = INTEGER(na)[2];
+    G->msq = INTEGER(na)[3];
+    G->ns = INTEGER(na)[4];
+    G->n = n = asInteger(pn);
+    G->ncond = asInteger(sncond);
+    G->m = m = asInteger(pm);
+    G->params = Calloc(G->mp + G->mq + G->msp + G->msq + G->m, double);
+    G->p = ip = G->ns*G->msp + G->mp;
+    G->q = iq = G->ns*G->msq + G->mq;
+    G->r = ir = max(ip, iq + 1);
+    G->np = np = (ir*(ir + 1))/2;
+    G->nrbar = max(1, np*(np - 1)/2);
+    G->trans = asInteger(ptrans);
+    G->a = Calloc(ir, double);
+    G->P = Calloc(np, double);
+    G->V = Calloc(np, double);
+    G->thetab = Calloc(np, double);
+    G->xnext = Calloc(np, double);
+    G->xrow = Calloc(np, double);
+    G->rbar = Calloc(G->nrbar, double);
+    G->w = Calloc(n, double);
+    G->wkeep = Calloc(n, double);
+    G->resid = Calloc(n, double);
+    G->phi = Calloc(ir, double);
+    G->theta = Calloc(ir, double);
+    G->reg = Calloc(1 + n*m, double); /* AIX can't calloc 0 items */
+    G->delta = asReal(dt);
+    for(i = 0; i < n; i++) G->w[i] = G->wkeep[i] = rx[i];
+    for(i = 0; i < n*m; i++) G->reg[i] = rxreg[i];
+    Starma_tag = install("STARMA_TAG");
+    res = R_MakeExternalPtr(G, Starma_tag, R_NilValue);
+    return res;
+}
+
+SEXP free_starma(SEXP pG)
+{
+    GET_STARMA;
+
+    Free(G->params); Free(G->a); Free(G->P); Free(G->V); Free(G->thetab);
+    Free(G->xnext); Free(G->xrow); Free(G->rbar);
+    Free(G->w); Free(G->wkeep); Free(G->resid); Free(G->phi); Free(G->theta);
+    Free(G->reg); Free(G);
+    return R_NilValue;
+}
+
+SEXP Starma_method(SEXP pG, SEXP method)
+{
+    GET_STARMA;
+
+    G->method = asInteger(method);
+    return R_NilValue;
+}
+
+SEXP Dotrans(SEXP pG, SEXP x)
+{
+    SEXP y = allocVector(REALSXP, LENGTH(x));
+    GET_STARMA;
+
+    dotrans(G, REAL(x), REAL(y), 1);
+    return y;
+}
+
+SEXP set_trans(SEXP pG, SEXP ptrans)
+{
+    GET_STARMA;
+
+    G->trans = asInteger(ptrans);
+    return R_NilValue;
+}
+
+SEXP arma0fa(SEXP pG, SEXP inparams)
+{
+    int i, j, ifault = 0, it, streg;
+    double sumlog, ssq, tmp, ans;
+
+    GET_STARMA;
+    dotrans(G, REAL(inparams), G->params, G->trans);
+
+    if(G->ns > 0) {
+	/* expand out seasonal ARMA models */
+	for(i = 0; i < G->mp; i++) G->phi[i] = G->params[i];
+	for(i = 0; i < G->mq; i++) G->theta[i] = G->params[i + G->mp];
+	for(i = G->mp; i < G->p; i++) G->phi[i] = 0.0;
+	for(i = G->mq; i < G->q; i++) G->theta[i] = 0.0;
+	for(j = 0; j < G->msp; j++) {
+	    G->phi[(j + 1)*G->ns - 1] += G->params[j + G->mp + G->mq];
+	    for(i = 0; i < G->mp; i++)
+		G->phi[(j + 1)*G->ns + i] -= G->params[i]*
+		    G->params[j + G->mp + G->mq];
+	}
+	for(j = 0; j < G->msq; j++) {
+	    G->theta[(j + 1)*G->ns - 1] +=
+		G->params[j + G->mp + G->mq + G->msp];
+	    for(i = 0; i < G->mq; i++)
+		G->theta[(j + 1)*G->ns + i] += G->params[i + G->mp]*
+		    G->params[j + G->mp + G->mq + G->msp];
+	}
+    } else {
+	for(i = 0; i < G->mp; i++) G->phi[i] = G->params[i];
+	for(i = 0; i < G->mq; i++) G->theta[i] = G->params[i + G->mp];
+    }
+
+    streg = G->mp + G->mq + G->msp + G->msq;
+    if(G->m > 0) {
+	for(i = 0; i < G->n; i++) {
+	    tmp = G->wkeep[i];
+	    for(j = 0; j < G->m; j++)
+		tmp -= G->reg[i + G->n*j] * G->params[streg + j];
+	    G->w[i] = tmp;
+	}
+    }
+
+    if(G->method == 1) {
+	int p = G->mp + G->ns * G->msp, q = G->mq + G->ns * G->msq, nu = 0;
+	ssq = 0.0;
+	for(i = 0; i < G->ncond; i++) G->resid[i] = 0.0;
+	for(i = G->ncond; i < G->n; i++) {
+	    tmp = G->w[i];
+	    for(j = 0; j < min(i - G->ncond, p); j++)
+		tmp -= G->phi[j] * G->w[i - j - 1];
+	    for(j = 0; j < min(i - G->ncond, q); j++)
+		tmp -= G->theta[j] * G->resid[i - j - 1];
+	    G->resid[i] = tmp;
+	    if(!ISNAN(tmp)) {
+		nu++;
+		ssq += tmp * tmp;
+	    }
+	}
+	G->s2 = ssq/(double)(nu);
+	ans = 0.5 * log(G->s2);
+    } else {
+	starma(G, &ifault);
+	if(ifault) error(_("starma error code %d"), ifault);
+	sumlog = 0.0;
+	ssq = 0.0;
+	it = 0;
+	karma(G, &sumlog, &ssq, 1, &it);
+	G->s2 = ssq/(double)G->nused;
+	ans = 0.5*(log(ssq/(double)G->nused) + sumlog/(double)G->nused);
+    }
+    return ScalarReal(ans);
+}
+
+SEXP get_s2(SEXP pG)
+{
+    GET_STARMA;
+    return ScalarReal(G->s2);
+}
+
+SEXP get_resid(SEXP pG)
+{
+    SEXP res;
+    int i;
+    double *rres;
+    GET_STARMA;
+
+    res = allocVector(REALSXP, G->n);
+    rres = REAL(res);
+    for(i = 0; i < G->n; i++) rres[i] = G->resid[i];
+    return res;
+}
+
+SEXP arma0_kfore(SEXP pG, SEXP pd, SEXP psd, SEXP nahead)
+{
+    int dd = asInteger(pd);
+    int d, il = asInteger(nahead), ifault = 0, i, j;
+    double *del, *del2;
+    SEXP res, x, var;
+    GET_STARMA;
+
+    PROTECT(res = allocVector(VECSXP, 2));
+    SET_VECTOR_ELT(res, 0, x = allocVector(REALSXP, il));
+    SET_VECTOR_ELT(res, 1, var = allocVector(REALSXP, il));
+
+    d = dd + G->ns * asInteger(psd);
+
+    del = (double *) R_alloc(d + 1, sizeof(double));
+    del2 = (double *) R_alloc(d + 1, sizeof(double));
+    del[0] = 1;
+    for(i = 1; i <= d; i++) del[i] = 0;
+    for (j = 0; j < dd; j++) {
+	for(i = 0; i <= d; i++) del2[i] = del[i];
+	for(i = 0; i <= d - 1; i++) del[i+1] -= del2[i];
+    }
+    for (j = 0; j < asInteger(psd); j++) {
+	for(i = 0; i <= d; i++) del2[i] = del[i];
+	for(i = 0; i <= d - G->ns; i++) del[i + G->ns] -= del2[i];
+    }
+    for(i = 1; i <= d; i++) del[i] *= -1;
+
+
+    forkal(G, d, il, del + 1, REAL(x), REAL(var), &ifault);
+    if(ifault) error(_("forkal error code %d"), ifault);
+    UNPROTECT(1);
+    return res;
+}
+
+static void artoma(int p, double *phi, double *psi, int npsi)
+{
+    int i, j;
+
+    for(i = 0; i < p; i++) psi[i] = phi[i];
+    for(i = p; i < npsi; i++) psi[i] = 0.0;
+    for(i = 0; i < npsi - p - 1; i++)
+	for(j = 0; j < p; j++) psi[i + j + 1] += phi[j]*psi[i];
+}
+
+SEXP ar2ma(SEXP ar, SEXP npsi)
+{
+    ar = PROTECT(coerceVector(ar, REALSXP));
+    int p = LENGTH(ar), ns = asInteger(npsi), ns1 = ns + p + 1;
+    SEXP psi = PROTECT(allocVector(REALSXP, ns1));
+    artoma(p, REAL(ar), REAL(psi), ns1);
+    SEXP ans = lengthgets(psi, ns);
+    UNPROTECT(2);
+    return ans;
+}
+
+static void partrans(int p, double *raw, double *new)
+{
+    int j, k;
+    double a, work[100];
+
+    if(p > 100) error(_("can only transform 100 pars in arima0"));
+
+    /* Step one: map (-Inf, Inf) to (-1, 1) via tanh
+       The parameters are now the pacf phi_{kk} */
+    for(j = 0; j < p; j++) work[j] = new[j] = tanh(raw[j]);
+    /* Step two: run the Durbin-Levinson recursions to find phi_{j.},
+       j = 2, ..., p and phi_{p.} are the autoregression coefficients */
+    for(j = 1; j < p; j++) {
+	a = new[j];
+	for(k = 0; k < j; k++)
+	    work[k] -= a * new[j - k - 1];
+	for(k = 0; k < j; k++) new[k] = work[k];
+    }
+}
+
+static void dotrans(Starma G, double *raw, double *new, int trans)
+{
+    int i, v, n = G->mp + G->mq + G->msp + G->msq + G->m;
+
+    for(i = 0; i < n; i++) new[i] = raw[i];
+    if(trans) {
+	partrans(G->mp, raw, new);
+	v = G->mp;
+	partrans(G->mq, raw + v, new + v);
+	v += G->mq;
+	partrans(G->msp, raw + v, new + v);
+	v += G->msp;
+	partrans(G->msq, raw + v, new + v);
+    }
+}
+
+#if !defined(atanh) && defined(HAVE_DECL_ATANH) && !HAVE_DECL_ATANH
+extern double atanh(double x);
+#endif
+static void invpartrans(int p, double *phi, double *new)
+{
+    int j, k;
+    double a, work[100];
+
+    if(p > 100) error(_("can only transform 100 pars in arima0"));
+
+    for(j = 0; j < p; j++) work[j] = new[j] = phi[j];
+    /* Run the Durbin-Levinson recursions backwards
+       to find the PACF phi_{j.} from the autoregression coefficients */
+    for(j = p - 1; j > 0; j--) {
+	a = new[j];
+	for(k = 0; k < j; k++)
+	    work[k]  = (new[k] + a * new[j - k - 1]) / (1 - a * a);
+	for(k = 0; k < j; k++) new[k] = work[k];
+    }
+    for(j = 0; j < p; j++) new[j] = atanh(new[j]);
+}
+
+SEXP Invtrans(SEXP pG, SEXP x)
+{
+    SEXP y = allocVector(REALSXP, LENGTH(x));
+    int i, v, n;
+    double *raw = REAL(x), *new = REAL(y);
+    GET_STARMA;
+
+    n = G->mp + G->mq + G->msp + G->msq;
+
+    v = 0;
+    invpartrans(G->mp, raw + v, new + v);
+    v += G->mp;
+    invpartrans(G->mq, raw + v, new + v);
+    v += G->mq;
+    invpartrans(G->msp, raw + v, new + v);
+    v += G->msp;
+    invpartrans(G->msq, raw + v, new + v);
+    for(i = n; i < n + G->m; i++) new[i] = raw[i];
+    return y;
+}
+
+#define eps 1e-3
+SEXP Gradtrans(SEXP pG, SEXP x)
+{
+    SEXP y = allocMatrix(REALSXP, LENGTH(x), LENGTH(x));
+    int i, j, v, n;
+    double *raw = REAL(x), *A = REAL(y), w1[100], w2[100], w3[100];
+    GET_STARMA;
+
+    n = G->mp + G->mq + G->msp + G->msq + G->m;
+    for(i = 0; i < n; i++)
+	for(j = 0; j < n; j++)
+	    A[i + j*n] = (i == j);
+    if(G->mp > 0) {
+	for(i = 0; i < G->mp; i++) w1[i] = raw[i];
+	partrans(G->mp, w1, w2);
+	for(i = 0; i < G->mp; i++) {
+	    w1[i] += eps;
+	    partrans(G->mp, w1, w3);
+	    for(j = 0; j < G->mp; j++) A[i + j*n] = (w3[j] - w2[j])/eps;
+	    w1[i] -= eps;
+	}
+    }
+    if(G->mq > 0) {
+	v = G->mp;
+	for(i = 0; i < G->mq; i++) w1[i] = raw[i + v];
+	partrans(G->mq, w1, w2);
+	for(i = 0; i < G->mq; i++) {
+	    w1[i] += eps;
+	    partrans(G->mq, w1, w3);
+	    for(j = 0; j < G->mq; j++) A[i + v + j*n] = (w3[j] - w2[j])/eps;
+	    w1[i] -= eps;
+	}
+    }
+    if(G->msp > 0) {
+	v = G->mp + G->mq;
+	for(i = 0; i < G->msp; i++) w1[i] = raw[i + v];
+	partrans(G->msp, w1, w2);
+	for(i = 0; i < G->msp; i++) {
+	    w1[i] += eps;
+	    partrans(G->msp, w1, w3);
+	    for(j = 0; j < G->msp; j++)
+		A[i + v + (j+v)*n] = (w3[j] - w2[j])/eps;
+	    w1[i] -= eps;
+	}
+    }
+    if(G->msq > 0) {
+	v = G->mp + G->mq + G->msp;
+	for(i = 0; i < G->msq; i++) w1[i] = raw[i + v];
+	partrans(G->msq, w1, w2);
+	for(i = 0; i < G->msq; i++) {
+	    w1[i] += eps;
+	    partrans(G->msq, w1, w3);
+	    for(j = 0; j < G->msq; j++)
+		A[i + v + (j+v)*n] = (w3[j] - w2[j])/eps;
+	    w1[i] -= eps;
+	}
+    }
+    return y;
+}
+
+SEXP
+ARMAtoMA(SEXP ar, SEXP ma, SEXP lag_max)
+{
+    int i, j, p = LENGTH(ar), q = LENGTH(ma), m = asInteger(lag_max);
+    double *phi = REAL(ar), *theta = REAL(ma), *psi, tmp;
+    SEXP res;
+
+    if(m <= 0 || m == NA_INTEGER)
+	error(_("invalid value of lag.max"));
+    PROTECT(res = allocVector(REALSXP, m));
+    psi = REAL(res);
+    for(i = 0; i < m; i++) {
+	tmp = (i < q) ? theta[i] : 0.0;
+	for(j = 0; j < min(i+1, p); j++)
+	    tmp += phi[j] * ((i-j-1 >= 0) ? psi[i-j-1] : 1.0);
+	psi[i] = tmp;
+    }
+    UNPROTECT(1);
+    return res;
+}
diff --git a/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/portsrc.f b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/portsrc.f
new file mode 100644
index 0000000000000000000000000000000000000000..46838e555378b5aea9f67c0fdc1c3b3ea95de4bd
--- /dev/null
+++ b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/portsrc.f
@@ -0,0 +1,12378 @@
+      SUBROUTINE  DRN2G(D, DR, IV, LIV, LV, N, ND, N1, N2, P, R,
+     1                  RD, V, X)
+C
+C *** REVISED ITERATION DRIVER FOR NL2SOL (VERSION 2.3) ***
+C
+      INTEGER LIV, LV, N, ND, N1, N2, P
+      INTEGER IV(LIV)
+      DOUBLE PRECISION D(P), DR(ND,P), R(ND), RD(ND), V(LV), X(P)
+C
+C--------------------------  PARAMETER USAGE  --------------------------
+C
+C D........ SCALE VECTOR.
+C DR....... DERIVATIVES OF R AT X.
+C IV....... INTEGER VALUES ARRAY.
+C LIV...... LENGTH OF IV... LIV MUST BE AT LEAST P + 82.
+C LV....... LENGTH OF V...  LV  MUST BE AT LEAST 105 + P*(2*P+16).
+C N........ TOTAL NUMBER OF RESIDUALS.
+C ND....... MAX. NO. OF RESIDUALS PASSED ON ONE CALL.
+C N1....... LOWEST  ROW INDEX FOR RESIDUALS SUPPLIED THIS TIME.
+C N2....... HIGHEST ROW INDEX FOR RESIDUALS SUPPLIED THIS TIME.
+C P........ NUMBER OF PARAMETERS (COMPONENTS OF X) BEING ESTIMATED.
+C R........ RESIDUALS.
+C RD....... RD(I) = SQRT(G(I)**T * H(I)**-1 * G(I)) ON OUTPUT WHEN
+C        IV(RDREQ) IS NONZERO.   DRN2G SETS IV(REGD) = 1 IF RD
+C        IS SUCCESSFULLY COMPUTED, TO 0 IF NO ATTEMPT WAS MADE
+C        TO COMPUTE IT, AND TO -1 IF H (THE FINITE-DIFFERENCE HESSIAN)
+C        WAS INDEFINITE.  IF ND .GE. N, THEN RD IS ALSO USED AS
+C        TEMPORARY STORAGE.
+C V........ FLOATING-POINT VALUES ARRAY.
+C X........ PARAMETER VECTOR BEING ESTIMATED (INPUT = INITIAL GUESS,
+C             OUTPUT = BEST VALUE FOUND).
+C
+C  ***  DISCUSSION  ***
+C
+C  NOTE... NL2SOL AND NL2ITR (MENTIONED BELOW) ARE DESCRIBED IN
+C  ACM TRANS. MATH. SOFTWARE, VOL. 7, PP. 369-383 (AN ADAPTIVE
+C  NONLINEAR LEAST-SQUARES ALGORITHM, BY J.E. DENNIS, D.M. GAY,
+C  AND R.E. WELSCH).
+C
+C     THIS ROUTINE CARRIES OUT ITERATIONS FOR SOLVING NONLINEAR
+C  LEAST SQUARES PROBLEMS.  WHEN ND = N, IT IS SIMILAR TO NL2ITR
+C  (WITH J = DR), EXCEPT THAT R(X) AND DR(X) NEED NOT BE INITIALIZED
+C  WHEN  DRN2G IS CALLED WITH IV(1) = 0 OR 12.   DRN2G ALSO ALLOWS
+C  R AND DR TO BE SUPPLIED ROW-WISE -- JUST SET ND = 1 AND CALL
+C   DRN2G ONCE FOR EACH ROW WHEN PROVIDING RESIDUALS AND JACOBIANS.
+C     ANOTHER NEW FEATURE IS THAT CALLING  DRN2G WITH IV(1) = 13
+C  CAUSES STORAGE ALLOCATION ONLY TO BE PERFORMED -- ON RETURN, SUCH
+C  COMPONENTS AS IV(G) (THE FIRST SUBSCRIPT IN G OF THE GRADIENT)
+C  AND IV(S) (THE FIRST SUBSCRIPT IN V OF THE S LOWER TRIANGLE OF
+C  THE S MATRIX) WILL HAVE BEEN SET (UNLESS LIV OR LV IS TOO SMALL),
+C  AND IV(1) WILL HAVE BEEN SET TO 14. CALLING  DRN2G WITH IV(1) = 14
+C  CAUSES EXECUTION OF THE ALGORITHM TO BEGIN UNDER THE ASSUMPTION
+C  THAT STORAGE HAS BEEN ALLOCATED.
+C
+C ***  SUPPLYING R AND DR  ***
+C
+C      DRN2G USES IV AND V IN THE SAME WAY AS NL2SOL, WITH A SMALL
+C  NUMBER OF OBVIOUS CHANGES.  ONE DIFFERENCE BETWEEN  DRN2G AND
+C  NL2ITR IS THAT INITIAL FUNCTION AND GRADIENT INFORMATION NEED NOT
+C  BE SUPPLIED IN THE VERY FIRST CALL ON  DRN2G, THE ONE WITH
+C  IV(1) = 0 OR 12.  ANOTHER DIFFERENCE IS THAT  DRN2G RETURNS WITH
+C  IV(1) = -2 WHEN IT WANTS ANOTHER LOOK AT THE OLD JACOBIAN MATRIX
+C  AND THE CURRENT RESIDUAL -- THE ONE CORRESPONDING TO X AND
+C  IV(NFGCAL).  IT THEN RETURNS WITH IV(1) = -3 WHEN IT WANTS TO SEE
+C  BOTH THE NEW RESIDUAL AND THE NEW JACOBIAN MATRIX AT ONCE.  NOTE
+C  THAT IV(NFGCAL) = IV(7) CONTAINS THE VALUE THAT IV(NFCALL) = IV(6)
+C  HAD WHEN THE CURRENT RESIDUAL WAS EVALUATED.  ALSO NOTE THAT THE
+C  VALUE OF X CORRESPONDING TO THE OLD JACOBIAN MATRIX IS STORED IN
+C  V, STARTING AT V(IV(X0)) = V(IV(43)).
+C     ANOTHER NEW RETURN...  DRN2G IV(1) = -1 WHEN IT WANTS BOTH THE
+C  RESIDUAL AND THE JACOBIAN TO BE EVALUATED AT X.
+C     A NEW RESIDUAL VECTOR MUST BE SUPPLIED WHEN  DRN2G RETURNS WITH
+C  IV(1) = 1 OR -1.  THIS TAKES THE FORM OF VALUES OF R(I,X) PASSED
+C  IN R(I-N1+1), I = N1(1)N2.  YOU MAY PASS ALL THESE VALUES AT ONCE
+C  (I.E., N1 = 1 AND N2 = N) OR IN PIECES BY MAKING SEVERAL CALLS ON
+C   DRN2G.  EACH TIME  DRN2G RETURNS WITH IV(1) = 1, N1 WILL HAVE
+C  BEEN SET TO THE INDEX OF THE NEXT RESIDUAL THAT  DRN2G EXPECTS TO
+C  SEE, AND N2 WILL BE SET TO THE INDEX OF THE HIGHEST RESIDUAL THAT
+C  COULD BE GIVEN ON THE NEXT CALL, I.E., N2 = N1 + ND - 1.  (THUS
+C  WHEN  DRN2G FIRST RETURNS WITH IV(1) = 1 FOR A NEW X, IT WILL
+C  HAVE SET N1 TO 1 AND N2 TO MIN(ND,N).)  THE CALLER MAY PROVIDE
+C  FEWER THAN N2-N1+1 RESIDUALS ON THE NEXT CALL BY SETTING N2 TO
+C  A SMALLER VALUE.   DRN2G ASSUMES IT HAS SEEN ALL THE RESIDUALS
+C  FOR THE CURRENT X WHEN IT IS CALLED WITH N2 .GE. N.
+C    EXAMPLE... SUPPOSE N = 80 AND THAT R IS TO BE PASSED IN 8
+C  BLOCKS OF SIZE 10.  THE FOLLOWING CODE WOULD DO THE JOB.
+C
+C      N = 80
+C      ND = 10
+C      ...
+C      DO 10 K = 1, 8
+C           ***  COMPUTE R(I,X) FOR I = 10*K-9 TO 10*K  ***
+C           ***  AND STORE THEM IN R(1),...,R(10)  ***
+C           CALL  DRN2G(..., R, ...)
+C   10      CONTINUE
+C
+C     THE SITUATION IS SIMILAR WHEN GRADIENT INFORMATION IS
+C  REQUIRED, I.E., WHEN  DRN2G RETURNS WITH IV(1) = 2, -1, OR -2.
+C  NOTE THAT  DRN2G OVERWRITES R, BUT THAT IN THE SPECIAL CASE OF
+C  N1 = 1 AND N2 = N ON PREVIOUS CALLS,  DRN2G NEVER RETURNS WITH
+C  IV(1) = -2.  IT SHOULD BE CLEAR THAT THE PARTIAL DERIVATIVE OF
+C  R(I,X) WITH RESPECT TO X(L) IS TO BE STORED IN DR(I-N1+1,L),
+C  L = 1(1)P, I = N1(1)N2.  IT IS ESSENTIAL THAT R(I) AND DR(I,L)
+C  ALL CORRESPOND TO THE SAME RESIDUALS WHEN IV(1) = -1 OR -2.
+C
+C  ***  COVARIANCE MATRIX  ***
+C
+C     IV(RDREQ) = IV(57) TELLS WHETHER TO COMPUTE A COVARIANCE
+C  MATRIX AND/OR REGRESSION DIAGNOSTICS... 0 MEANS NEITHER,
+C  1 MEANS COVARIANCE MATRIX ONLY, 2 MEANS REG. DIAGNOSTICS ONLY,
+C  3 MEANS BOTH.  AS WITH NL2SOL, IV(COVREQ) = IV(15) TELLS WHAT
+C  HESSIAN APPROXIMATION TO USE IN THIS COMPUTING.
+C
+C  ***  REGRESSION DIAGNOSTICS  ***
+C
+C     SEE THE COMMENTS IN SUBROUTINE   DN2G.
+C
+C  ***  GENERAL  ***
+C
+C     CODED BY DAVID M. GAY.
+C
+C+++++++++++++++++++++++++++++  DECLARATIONS  ++++++++++++++++++++++++++
+C
+C  ***  INTRINSIC FUNCTIONS  ***
+C/+
+      INTEGER IABS, MOD
+C/
+C  ***  EXTERNAL FUNCTIONS AND SUBROUTINES  ***
+C
+      DOUBLE PRECISION DD7TPR, DV2NRM
+      EXTERNAL DC7VFN,DIVSET, DD7TPR,DD7UPD,DG7LIT,DITSUM,DL7VML,
+     1         DN2CVP, DN2LRD, DQ7APL,DQ7RAD,DV7CPY, DV7SCP, DV2NRM
+C
+C DC7VFN... FINISHES COVARIANCE COMPUTATION.
+C DIVSET.... PROVIDES DEFAULT IV AND V INPUT COMPONENTS.
+C DD7TPR... COMPUTES INNER PRODUCT OF TWO VECTORS.
+C DD7UPD...  UPDATES SCALE VECTOR D.
+C DG7LIT.... PERFORMS BASIC MINIMIZATION ALGORITHM.
+C DITSUM.... PRINTS ITERATION SUMMARY, INFO ABOUT INITIAL AND FINAL X.
+C DL7VML.... COMPUTES L * V, V = VECTOR, L = LOWER TRIANGULAR MATRIX.
+C DN2CVP... PRINTS COVARIANCE MATRIX.
+C DN2LRD... COMPUTES REGRESSION DIAGNOSTICS.
+C DQ7APL... APPLIES QR TRANSFORMATIONS STORED BY DQ7RAD.
+C DQ7RAD.... ADDS A NEW BLOCK OF ROWS TO QR DECOMPOSITION.
+C DV7CPY.... COPIES ONE VECTOR TO ANOTHER.
+C DV7SCP... SETS ALL ELEMENTS OF A VECTOR TO A SCALAR.
+C
+C  ***  LOCAL VARIABLES  ***
+C
+      INTEGER G1, GI, I, IV1, IVMODE, JTOL1, K, L, LH, NN, QTR1,
+     1        RMAT1, YI, Y1
+      DOUBLE PRECISION T
+C
+      DOUBLE PRECISION HALF, ZERO
+C
+C  ***  SUBSCRIPTS FOR IV AND V  ***
+C
+      INTEGER CNVCOD, COVMAT, COVREQ, DINIT, DTYPE, DTINIT, D0INIT, F,
+     1        FDH, G, H, IPIVOT, IVNEED, JCN, JTOL, LMAT, MODE,
+     2        NEXTIV, NEXTV, NF0, NF00, NF1, NFCALL, NFCOV, NFGCAL,
+     3        NGCALL, NGCOV, QTR, RDREQ, REGD, RESTOR, RLIMIT, RMAT,
+     4        TOOBIG, VNEED, Y
+C
+      PARAMETER (HALF=0.5D+0, ZERO=0.D+0)
+C
+C  ***  IV SUBSCRIPT VALUES  ***
+C
+      PARAMETER (CNVCOD=55, COVMAT=26, COVREQ=15, DTYPE=16, FDH=74,
+     1           G=28, H=56, IPIVOT=76, IVNEED=3, JCN=66, JTOL=59,
+     2           LMAT=42, MODE=35, NEXTIV=46, NEXTV=47, NFCALL=6,
+     3           NFCOV=52, NF0=68, NF00=81, NF1=69, NFGCAL=7, NGCALL=30,
+     4           NGCOV=53, QTR=77, RESTOR=9, RMAT=78, RDREQ=57, REGD=67,
+     5           TOOBIG=2, VNEED=4, Y=48)
+C
+C  ***  V SUBSCRIPT VALUES  ***
+C
+      PARAMETER (DINIT=38, DTINIT=39, D0INIT=40, F=10, RLIMIT=46)
+C
+C+++++++++++++++++++++++++++++++  BODY  ++++++++++++++++++++++++++++++++
+C
+      LH = P * (P+1) / 2
+      IF (IV(1) .EQ. 0) CALL DIVSET(1, IV, LIV, LV, V)
+      IV1 = IV(1)
+      IF (IV1 .GT. 2) GO TO 10
+         NN = N2 - N1 + 1
+         IV(RESTOR) = 0
+         I = IV1 + 4
+         IF (IV(TOOBIG) .EQ. 0) GO TO (150, 130, 150, 120, 120, 150), I
+         IF (I .NE. 5) IV(1) = 2
+         GO TO 40
+C
+C  ***  FRESH START OR RESTART -- CHECK INPUT INTEGERS  ***
+C
+ 10   IF (ND .LE. 0) GO TO 210
+      IF (P .LE. 0) GO TO 210
+      IF (N .LE. 0) GO TO 210
+      IF (IV1 .EQ. 14) GO TO 30
+      IF (IV1 .GT. 16) GO TO 300
+      IF (IV1 .LT. 12) GO TO 40
+      IF (IV1 .EQ. 12) IV(1) = 13
+      IF (IV(1) .NE. 13) GO TO 20
+      IV(IVNEED) = IV(IVNEED) + P
+      IV(VNEED) = IV(VNEED) + P*(P+13)/2
+ 20   CALL DG7LIT(D, X, IV, LIV, LV, P, P, V, X, X)
+      IF (IV(1) .NE. 14) GO TO 999
+C
+C  ***  STORAGE ALLOCATION  ***
+C
+      IV(IPIVOT) = IV(NEXTIV)
+      IV(NEXTIV) = IV(IPIVOT) + P
+      IV(Y) = IV(NEXTV)
+      IV(G) = IV(Y) + P
+      IV(JCN) = IV(G) + P
+      IV(RMAT) = IV(JCN) + P
+      IV(QTR) = IV(RMAT) + LH
+      IV(JTOL) = IV(QTR) + P
+      IV(NEXTV) = IV(JTOL) + 2*P
+      IF (IV1 .EQ. 13) GO TO 999
+C
+ 30   JTOL1 = IV(JTOL)
+      IF (V(DINIT) .GE. ZERO) CALL DV7SCP(P, D, V(DINIT))
+      IF (V(DTINIT) .GT. ZERO) CALL DV7SCP(P, V(JTOL1), V(DTINIT))
+      I = JTOL1 + P
+      IF (V(D0INIT) .GT. ZERO) CALL DV7SCP(P, V(I), V(D0INIT))
+      IV(NF0) = 0
+      IV(NF1) = 0
+      IF (ND .GE. N) GO TO 40
+C
+C  ***  SPECIAL CASE HANDLING OF FIRST FUNCTION AND GRADIENT EVALUATION
+C  ***  -- ASK FOR BOTH RESIDUAL AND JACOBIAN AT ONCE
+C
+      G1 = IV(G)
+      Y1 = IV(Y)
+      CALL DG7LIT(D, V(G1), IV, LIV, LV, P, P, V, X, V(Y1))
+      IF (IV(1) .NE. 1) GO TO 220
+      V(F) = ZERO
+      CALL DV7SCP(P, V(G1), ZERO)
+      IV(1) = -1
+      QTR1 = IV(QTR)
+      CALL DV7SCP(P, V(QTR1), ZERO)
+      IV(REGD) = 0
+      RMAT1 = IV(RMAT)
+      GO TO 100
+C
+ 40   G1 = IV(G)
+      Y1 = IV(Y)
+      CALL DG7LIT(D, V(G1), IV, LIV, LV, P, P, V, X, V(Y1))
+      IF (IV(1) .EQ. 2) GO TO 60
+      IF (IV(1) .GT. 2) GO TO 220
+C
+      V(F) = ZERO
+      IF (IV(NF1) .EQ. 0) GO TO 260
+      IF (IV(RESTOR) .NE. 2) GO TO 260
+      IV(NF0) = IV(NF1)
+      CALL DV7CPY(N, RD, R)
+      IV(REGD) = 0
+      GO TO 260
+C
+ 60   CALL DV7SCP(P, V(G1), ZERO)
+      IF (IV(MODE) .GT. 0) GO TO 230
+      RMAT1 = IV(RMAT)
+      QTR1 = IV(QTR)
+      CALL DV7SCP(P, V(QTR1), ZERO)
+      IV(REGD) = 0
+      IF (ND .LT. N) GO TO 90
+      IF (N1 .NE. 1) GO TO 90
+      IF (IV(MODE) .LT. 0) GO TO 100
+      IF (IV(NF1) .EQ. IV(NFGCAL)) GO TO 70
+         IF (IV(NF0) .NE. IV(NFGCAL)) GO TO 90
+            CALL DV7CPY(N, R, RD)
+            GO TO 80
+ 70   CALL DV7CPY(N, RD, R)
+ 80   CALL DQ7APL(ND, N, P, DR, RD, 0)
+      CALL DL7VML(P, V(Y1), V(RMAT1), RD)
+      GO TO 110
+C
+ 90   IV(1) = -2
+      IF (IV(MODE) .LT. 0) IV(1) = -1
+ 100  CALL DV7SCP(P, V(Y1), ZERO)
+ 110  CALL DV7SCP(LH, V(RMAT1), ZERO)
+      GO TO 260
+C
+C  ***  COMPUTE F(X)  ***
+C
+ 120  T = DV2NRM(NN, R)
+      IF (T .GT. V(RLIMIT)) GO TO 200
+      V(F) = V(F)  +  HALF * T**2
+      IF (N2 .LT. N) GO TO 270
+      IF (N1 .EQ. 1) IV(NF1) = IV(NFCALL)
+      GO TO 40
+C
+C  ***  COMPUTE Y  ***
+C
+ 130  Y1 = IV(Y)
+      YI = Y1
+      DO 140 L = 1, P
+         V(YI) = V(YI) + DD7TPR(NN, DR(1,L), R)
+         YI = YI + 1
+ 140     CONTINUE
+      IF (N2 .LT. N) GO TO 270
+         IV(1) = 2
+         IF (N1 .GT. 1) IV(1) = -3
+         GO TO 260
+C
+C  ***  COMPUTE GRADIENT INFORMATION  ***
+C
+ 150  IF (IV(MODE) .GT. P) GO TO 240
+      G1 = IV(G)
+      IVMODE = IV(MODE)
+      IF (IVMODE .LT. 0) GO TO 170
+      IF (IVMODE .EQ. 0) GO TO 180
+      IV(1) = 2
+C
+C  ***  COMPUTE GRADIENT ONLY (FOR USE IN COVARIANCE COMPUTATION)  ***
+C
+      GI = G1
+      DO 160 L = 1, P
+         V(GI) = V(GI) + DD7TPR(NN, R, DR(1,L))
+         GI = GI + 1
+ 160     CONTINUE
+      GO TO 190
+C
+C  *** COMPUTE INITIAL FUNCTION VALUE WHEN ND .LT. N ***
+C
+ 170  IF (N .LE. ND) GO TO 180
+         T = DV2NRM(NN, R)
+         IF (T .GT. V(RLIMIT)) GO TO 200
+         V(F) = V(F)  +  HALF * T**2
+C
+C  ***  UPDATE D IF DESIRED  ***
+C
+ 180  IF (IV(DTYPE) .GT. 0)
+     1      CALL DD7UPD(D, DR, IV, LIV, LV, N, ND, NN, N2, P, V)
+C
+C  ***  COMPUTE RMAT AND QTR  ***
+C
+      QTR1 = IV(QTR)
+      RMAT1 = IV(RMAT)
+      CALL DQ7RAD(NN, ND, P, V(QTR1), .TRUE., V(RMAT1), DR, R)
+      IV(NF1) = 0
+C
+ 190  IF (N2 .LT. N) GO TO 270
+      IF (IVMODE .GT. 0) GO TO 40
+      IV(NF00) = IV(NFGCAL)
+C
+C  ***  COMPUTE G FROM RMAT AND QTR  ***
+C
+      CALL DL7VML(P, V(G1), V(RMAT1), V(QTR1))
+      IV(1) = 2
+      IF (IVMODE .EQ. 0) GO TO 40
+      IF (N .LE. ND) GO TO 40
+C
+C  ***  FINISH SPECIAL CASE HANDLING OF FIRST FUNCTION AND GRADIENT
+C
+      Y1 = IV(Y)
+      IV(1) = 1
+      CALL DG7LIT(D, V(G1), IV, LIV, LV, P, P, V, X, V(Y1))
+      IF (IV(1) .NE. 2) GO TO 220
+      GO TO 40
+C
+C  ***  MISC. DETAILS  ***
+C
+C     ***  X IS OUT OF RANGE (OVERSIZE STEP)  ***
+C
+ 200  IV(TOOBIG) = 1
+      GO TO 40
+C
+C     ***  BAD N, ND, OR P  ***
+C
+ 210  IV(1) = 66
+      GO TO 300
+C
+C  ***  CONVERGENCE OBTAINED -- SEE WHETHER TO COMPUTE COVARIANCE  ***
+C
+ 220  IF (IV(COVMAT) .NE. 0) GO TO 290
+      IF (IV(REGD) .NE. 0) GO TO 290
+C
+C     ***  SEE IF CHOLESKY FACTOR OF HESSIAN IS AVAILABLE  ***
+C
+      K = IV(FDH)
+      IF (K .LE. 0) GO TO 280
+      IF (IV(RDREQ) .LE. 0) GO TO 290
+C
+C     ***  COMPUTE REGRESSION DIAGNOSTICS AND DEFAULT COVARIANCE IF
+C          DESIRED  ***
+C
+      I = 0
+      IF (MOD(IV(RDREQ),4) .GE. 2) I = 1
+      IF (MOD(IV(RDREQ),2) .EQ. 1 .AND. IABS(IV(COVREQ)) .LE. 1) I = I+2
+      IF (I .EQ. 0) GO TO 250
+      IV(MODE) = P + I
+      IV(NGCALL) = IV(NGCALL) + 1
+      IV(NGCOV) = IV(NGCOV) + 1
+      IV(CNVCOD) = IV(1)
+      IF (I .LT. 2) GO TO 230
+         L = IABS(IV(H))
+         CALL DV7SCP(LH, V(L), ZERO)
+ 230  IV(NFCOV) = IV(NFCOV) + 1
+      IV(NFCALL) = IV(NFCALL) + 1
+      IV(NFGCAL) = IV(NFCALL)
+      IV(1) = -1
+      GO TO 260
+C
+ 240  L = IV(LMAT)
+      CALL DN2LRD(DR, IV, V(L), LH, LIV, LV, ND, NN, P, R, RD, V)
+      IF (N2 .LT. N) GO TO 270
+      IF (N1 .GT. 1) GO TO 250
+C
+C     ***  ENSURE WE CAN RESTART -- AND MAKE RETURN STATE OF DR
+C     ***  INDEPENDENT OF WHETHER REGRESSION DIAGNOSTICS ARE COMPUTED.
+C     ***  USE STEP VECTOR (ALLOCATED BY DG7LIT) FOR SCRATCH.
+C
+      RMAT1 = IV(RMAT)
+      CALL DV7SCP(LH, V(RMAT1), ZERO)
+      CALL DQ7RAD(NN, ND, P, R, .FALSE., V(RMAT1), DR, R)
+      IV(NF1) = 0
+C
+C  ***  FINISH COMPUTING COVARIANCE  ***
+C
+ 250  L = IV(LMAT)
+      CALL DC7VFN(IV, V(L), LH, LIV, LV, N, P, V)
+      GO TO 290
+C
+C  ***  RETURN FOR MORE FUNCTION OR GRADIENT INFORMATION  ***
+C
+ 260  N2 = 0
+ 270  N1 = N2 + 1
+      N2 = N2 + ND
+      IF (N2 .GT. N) N2 = N
+      GO TO 999
+C
+C  ***  COME HERE FOR INDEFINITE FINITE-DIFFERENCE HESSIAN  ***
+C
+ 280  IV(COVMAT) = K
+      IV(REGD) = K
+C
+C  ***  PRINT SUMMARY OF FINAL ITERATION AND OTHER REQUESTED ITEMS  ***
+C
+ 290  G1 = IV(G)
+ 300  CALL DITSUM(D, V(G1), IV, LIV, LV, P, V, X)
+      IF (IV(1) .LE. 6 .AND. IV(RDREQ) .GT. 0)
+     1     CALL DN2CVP(IV, LIV, LV, P, V)
+C
+ 999  RETURN
+C  ***  LAST LINE OF  DRN2G FOLLOWS  ***
+      END
+      SUBROUTINE DL7SQR(N, A, L)
+C
+C  ***  COMPUTE  A = LOWER TRIANGLE OF  L*(L**T),  WITH BOTH
+C  ***  L  AND  A  STORED COMPACTLY BY ROWS.  (BOTH MAY OCCUPY THE
+C  ***  SAME STORAGE.
+C
+C  ***  PARAMETERS  ***
+C
+      INTEGER N
+      DOUBLE PRECISION A(*), L(*)
+C     DIMENSION A(N*(N+1)/2), L(N*(N+1)/2)
+C
+C  ***  LOCAL VARIABLES  ***
+C
+      INTEGER I, II, IJ, IK, IP1, I0, J, JJ, JK, J0, K, NP1
+      DOUBLE PRECISION T
+C
+      NP1 = N + 1
+      I0 = N*(N+1)/2
+      DO 30 II = 1, N
+         I = NP1 - II
+         IP1 = I + 1
+         I0 = I0 - I
+         J0 = I*(I+1)/2
+         DO 20 JJ = 1, I
+              J = IP1 - JJ
+              J0 = J0 - J
+              T = 0.0D0
+              DO 10 K = 1, J
+                   IK = I0 + K
+                   JK = J0 + K
+                   T = T + L(IK)*L(JK)
+ 10                CONTINUE
+              IJ = I0 + J
+              A(IJ) = T
+ 20           CONTINUE
+ 30      CONTINUE
+      RETURN
+      END
+      SUBROUTINE DRMNHB(B, D, FX, G, H, IV, LH, LIV, LV, N, V, X)
+C
+C  ***  CARRY OUT  DMNHB (SIMPLY BOUNDED MINIMIZATION) ITERATIONS,
+C  ***  USING HESSIAN MATRIX PROVIDED BY THE CALLER.
+C
+C  ***  PARAMETER DECLARATIONS  ***
+C
+      INTEGER LH, LIV, LV, N
+      INTEGER IV(LIV)
+      DOUBLE PRECISION B(2,N), D(N), FX, G(N), H(LH), V(LV), X(N)
+C
+C--------------------------  PARAMETER USAGE  --------------------------
+C
+C D.... SCALE VECTOR.
+C FX... FUNCTION VALUE.
+C G.... GRADIENT VECTOR.
+C H.... LOWER TRIANGLE OF THE HESSIAN, STORED ROWWISE.
+C IV... INTEGER VALUE ARRAY.
+C LH... LENGTH OF H = P*(P+1)/2.
+C LIV.. LENGTH OF IV (AT LEAST 59 + 3*N).
+C LV... LENGTH OF V (AT LEAST 78 + N*(N+27)/2).
+C N.... NUMBER OF VARIABLES (COMPONENTS IN X AND G).
+C V.... FLOATING-POINT VALUE ARRAY.
+C X.... PARAMETER VECTOR.
+C
+C  ***  DISCUSSION  ***
+C
+C        PARAMETERS IV, N, V, AND X ARE THE SAME AS THE CORRESPONDING
+C     ONES TO  DMNHB (WHICH SEE), EXCEPT THAT V CAN BE SHORTER (SINCE
+C     THE PART OF V THAT  DMNHB USES FOR STORING G AND H IS NOT NEEDED).
+C     MOREOVER, COMPARED WITH  DMNHB, IV(1) MAY HAVE THE TWO ADDITIONAL
+C     OUTPUT VALUES 1 AND 2, WHICH ARE EXPLAINED BELOW, AS IS THE USE
+C     OF IV(TOOBIG) AND IV(NFGCAL).  THE VALUE IV(G), WHICH IS AN
+C     OUTPUT VALUE FROM  DMNHB, IS NOT REFERENCED BY DRMNHB OR THE
+C     SUBROUTINES IT CALLS.
+C
+C IV(1) = 1 MEANS THE CALLER SHOULD SET FX TO F(X), THE FUNCTION VALUE
+C             AT X, AND CALL DRMNHB AGAIN, HAVING CHANGED NONE OF THE
+C             OTHER PARAMETERS.  AN EXCEPTION OCCURS IF F(X) CANNOT BE
+C             COMPUTED (E.G. IF OVERFLOW WOULD OCCUR), WHICH MAY HAPPEN
+C             BECAUSE OF AN OVERSIZED STEP.  IN THIS CASE THE CALLER
+C             SHOULD SET IV(TOOBIG) = IV(2) TO 1, WHICH WILL CAUSE
+C             DRMNHB TO IGNORE FX AND TRY A SMALLER STEP.  THE PARA-
+C             METER NF THAT  DMNH PASSES TO CALCF (FOR POSSIBLE USE BY
+C             CALCGH) IS A COPY OF IV(NFCALL) = IV(6).
+C IV(1) = 2 MEANS THE CALLER SHOULD SET G TO G(X), THE GRADIENT OF F AT
+C             X, AND H TO THE LOWER TRIANGLE OF H(X), THE HESSIAN OF F
+C             AT X, AND CALL DRMNHB AGAIN, HAVING CHANGED NONE OF THE
+C             OTHER PARAMETERS EXCEPT PERHAPS THE SCALE VECTOR D.
+C                  THE PARAMETER NF THAT  DMNHB PASSES TO CALCG IS
+C             IV(NFGCAL) = IV(7).  IF G(X) AND H(X) CANNOT BE EVALUATED,
+C             THEN THE CALLER MAY SET IV(NFGCAL) TO 0, IN WHICH CASE
+C             DRMNHB WILL RETURN WITH IV(1) = 65.
+C                  NOTE -- DRMNHB OVERWRITES H WITH THE LOWER TRIANGLE
+C             OF  DIAG(D)**-1 * H(X) * DIAG(D)**-1.
+C.
+C  ***  GENERAL  ***
+C
+C     CODED BY DAVID M. GAY (WINTER, SPRING 1983).
+C
+C        (SEE  DMNG AND  DMNH FOR REFERENCES.)
+C
+C+++++++++++++++++++++++++++  DECLARATIONS  ++++++++++++++++++++++++++++
+C
+C  ***  LOCAL VARIABLES  ***
+C
+      INTEGER DG1, DUMMY, I, IPI, IPIV2, IPN, J, K, L, LSTGST, NN1O2,
+     1        RSTRST, STEP0, STEP1, TD1, TEMP0, TEMP1, TG1, W1, X01, X11
+      DOUBLE PRECISION GI, T, XI
+C
+C     ***  CONSTANTS  ***
+C
+      DOUBLE PRECISION NEGONE, ONE, ONEP2, ZERO
+C
+C  ***  NO INTRINSIC FUNCTIONS  ***
+C
+C  ***  EXTERNAL FUNCTIONS AND SUBROUTINES  ***
+C
+      LOGICAL STOPX
+      DOUBLE PRECISION DD7TPR, DRLDST, DV2NRM
+      EXTERNAL DA7SST,DIVSET, DD7TPR,DD7DUP, DG7QSB, I7PNVR,DITSUM,
+     1        DPARCK, DRLDST, DS7IPR, DS7LVM, STOPX, DV2NRM,DV2AXY,
+     2        DV7CPY, DV7IPR, DV7SCP, DV7VMP
+C
+C DA7SST.... ASSESSES CANDIDATE STEP.
+C DIVSET.... PROVIDES DEFAULT IV AND V INPUT VALUES.
+C DD7TPR... RETURNS INNER PRODUCT OF TWO VECTORS.
+C DD7DUP.... UPDATES SCALE VECTOR D.
+C DG7QSB... COMPUTES APPROXIMATE OPTIMAL BOUNDED STEP.
+C I7PNVR... INVERTS PERMUTATION ARRAY.
+C DITSUM.... PRINTS ITERATION SUMMARY AND INFO ON INITIAL AND FINAL X.
+C DPARCK.... CHECKS VALIDITY OF INPUT IV AND V VALUES.
+C DRLDST... COMPUTES V(RELDX) = RELATIVE STEP SIZE.
+C DS7IPR... APPLIES PERMUTATION TO LOWER TRIANG. OF SYM. MATRIX.
+C DS7LVM... MULTIPLIES SYMMETRIC MATRIX TIMES VECTOR, GIVEN THE LOWER
+C             TRIANGLE OF THE MATRIX.
+C STOPX.... RETURNS .TRUE. IF THE BREAK KEY HAS BEEN PRESSED.
+C DV2NRM... RETURNS THE 2-NORM OF A VECTOR.
+C DV2AXY.... COMPUTES SCALAR TIMES ONE VECTOR PLUS ANOTHER.
+C DV7CPY.... COPIES ONE VECTOR TO ANOTHER.
+C DV7IPR... APPLIES PERMUTATION TO VECTOR.
+C DV7SCP... SETS ALL ELEMENTS OF A VECTOR TO A SCALAR.
+C DV7VMP... MULTIPLIES (OR DIVIDES) TWO VECTORS COMPONENTWISE.
+C
+C  ***  SUBSCRIPTS FOR IV AND V  ***
+C
+      INTEGER CNVCOD, DG, DGNORM, DINIT, DSTNRM, DTINIT, DTOL, DTYPE,
+     1        D0INIT, F, F0, FDIF, GTSTEP, INCFAC, IVNEED, IRC, KAGQT,
+     2        LMAT, LMAX0, LMAXS, MODE, MODEL, MXFCAL, MXITER, N0, NC,
+     3        NEXTIV, NEXTV, NFCALL, NFGCAL, NGCALL, NITER, PERM,
+     4        PHMXFC, PREDUC, RADFAC, RADINC, RADIUS, RAD0, RELDX,
+     5        RESTOR, STEP, STGLIM, STPPAR, TOOBIG, TUNER4, TUNER5,
+     6        VNEED, W, XIRC, X0
+C
+C  ***  IV SUBSCRIPT VALUES  ***
+C
+C  ***  (NOTE THAT NC AND N0 ARE STORED IN IV(G0) AND IV(STLSTG) RESP.)
+C
+      PARAMETER (CNVCOD=55, DG=37, DTOL=59, DTYPE=16, IRC=29, IVNEED=3,
+     1           KAGQT=33, LMAT=42, MODE=35, MODEL=5, MXFCAL=17,
+     2           MXITER=18, N0=41, NC=48, NEXTIV=46, NEXTV=47, NFCALL=6,
+     3           NFGCAL=7, NGCALL=30, NITER=31, PERM=58, RADINC=8,
+     4           RESTOR=9, STEP=40, STGLIM=11, TOOBIG=2, VNEED=4, W=34,
+     5           XIRC=13, X0=43)
+C
+C  ***  V SUBSCRIPT VALUES  ***
+C
+      PARAMETER (DGNORM=1, DINIT=38, DSTNRM=2, DTINIT=39, D0INIT=40,
+     1           F=10, F0=13, FDIF=11, GTSTEP=4, INCFAC=23, LMAX0=35,
+     2           LMAXS=36, PHMXFC=21, PREDUC=7, RADFAC=16, RADIUS=8,
+     3           RAD0=9, RELDX=17, STPPAR=5, TUNER4=29, TUNER5=30)
+C
+      PARAMETER (NEGONE=-1.D+0, ONE=1.D+0, ONEP2=1.2D+0, ZERO=0.D+0)
+C
+C+++++++++++++++++++++++++++++++  BODY  ++++++++++++++++++++++++++++++++
+C
+      I = IV(1)
+      IF (I .EQ. 1) GO TO 50
+      IF (I .EQ. 2) GO TO 60
+C
+C  ***  CHECK VALIDITY OF IV AND V INPUT VALUES  ***
+C
+      IF (IV(1) .EQ. 0) CALL DIVSET(2, IV, LIV, LV, V)
+      IF (IV(1) .LT. 12) GO TO 10
+      IF (IV(1) .GT. 13) GO TO 10
+         IV(VNEED) = IV(VNEED) + N*(N+27)/2 + 7
+         IV(IVNEED) = IV(IVNEED) + 3*N
+ 10   CALL DPARCK(2, D, IV, LIV, LV, N, V)
+      I = IV(1) - 2
+      IF (I .GT. 12) GO TO 999
+      NN1O2 = N * (N + 1) / 2
+      IF (LH .GE. NN1O2) GO TO (250,250,250,250,250,250,190,150,190,
+     1                          20,20,30), I
+         IV(1) = 81
+         GO TO 440
+C
+C  ***  STORAGE ALLOCATION  ***
+C
+ 20   IV(DTOL) = IV(LMAT) + NN1O2
+      IV(X0) = IV(DTOL) + 2*N
+      IV(STEP) = IV(X0) + 2*N
+      IV(DG) = IV(STEP) + 3*N
+      IV(W) = IV(DG) + 2*N
+      IV(NEXTV) = IV(W) + 4*N + 7
+      IV(NEXTIV) = IV(PERM) + 3*N
+      IF (IV(1) .NE. 13) GO TO 30
+         IV(1) = 14
+         GO TO 999
+C
+C  ***  INITIALIZATION  ***
+C
+ 30   IV(NITER) = 0
+      IV(NFCALL) = 1
+      IV(NGCALL) = 1
+      IV(NFGCAL) = 1
+      IV(MODE) = -1
+      IV(MODEL) = 1
+      IV(STGLIM) = 1
+      IV(TOOBIG) = 0
+      IV(CNVCOD) = 0
+      IV(RADINC) = 0
+      IV(NC) = N
+      V(RAD0) = ZERO
+      V(STPPAR) = ZERO
+      IF (V(DINIT) .GE. ZERO) CALL DV7SCP(N, D, V(DINIT))
+      K = IV(DTOL)
+      IF (V(DTINIT) .GT. ZERO) CALL DV7SCP(N, V(K), V(DTINIT))
+      K = K + N
+      IF (V(D0INIT) .GT. ZERO) CALL DV7SCP(N, V(K), V(D0INIT))
+C
+C  ***  CHECK CONSISTENCY OF B AND INITIALIZE IP ARRAY  ***
+C
+      IPI = IV(PERM)
+      DO 40 I = 1, N
+         IV(IPI) = I
+         IPI = IPI + 1
+         IF (B(1,I) .GT. B(2,I)) GO TO 420
+ 40      CONTINUE
+C
+C  ***  GET INITIAL FUNCTION VALUE  ***
+C
+      IV(1) = 1
+      GO TO 450
+C
+ 50   V(F) = FX
+      IF (IV(MODE) .GE. 0) GO TO 250
+      V(F0) = FX
+      IV(1) = 2
+      IF (IV(TOOBIG) .EQ. 0) GO TO 999
+         IV(1) = 63
+         GO TO 440
+C
+C  ***  MAKE SURE GRADIENT COULD BE COMPUTED  ***
+C
+ 60   IF (IV(TOOBIG) .EQ. 0) GO TO 70
+         IV(1) = 65
+         GO TO 440
+C
+C  ***  UPDATE THE SCALE VECTOR D  ***
+C
+ 70   DG1 = IV(DG)
+      IF (IV(DTYPE) .LE. 0) GO TO 90
+      K = DG1
+      J = 0
+      DO 80 I = 1, N
+         J = J + I
+         V(K) = H(J)
+         K = K + 1
+ 80      CONTINUE
+      CALL DD7DUP(D, V(DG1), IV, LIV, LV, N, V)
+C
+C  ***  COMPUTE SCALED GRADIENT AND ITS NORM  ***
+C
+ 90   DG1 = IV(DG)
+      CALL DV7VMP(N, V(DG1), G, D, -1)
+C
+C  ***  COMPUTE SCALED HESSIAN  ***
+C
+      K = 1
+      DO 110 I = 1, N
+         T = ONE / D(I)
+         DO 100 J = 1, I
+              H(K) = T * H(K) / D(J)
+              K = K + 1
+ 100          CONTINUE
+ 110     CONTINUE
+C
+C  ***  CHOOSE INITIAL PERMUTATION  ***
+C
+      IPI = IV(PERM)
+      IPN = IPI + N
+      IPIV2 = IPN - 1
+C     *** INVERT OLD PERMUTATION ARRAY ***
+      CALL I7PNVR(N, IV(IPN), IV(IPI))
+      K = IV(NC)
+      DO 130 I = 1, N
+         IF (B(1,I) .GE. B(2,I)) GO TO 120
+         XI = X(I)
+         GI = G(I)
+         IF (XI .LE. B(1,I) .AND. GI .GT. ZERO) GO TO 120
+         IF (XI .GE. B(2,I) .AND. GI .LT. ZERO) GO TO 120
+            IV(IPI) = I
+            IPI = IPI + 1
+            J = IPIV2 + I
+C           *** DISALLOW CONVERGENCE IF X(I) HAS JUST BEEN FREED ***
+            IF (IV(J) .GT. K) IV(CNVCOD) = 0
+            GO TO 130
+ 120     IPN = IPN - 1
+         IV(IPN) = I
+ 130     CONTINUE
+      IV(NC) = IPN - IV(PERM)
+C
+C  ***  PERMUTE SCALED GRADIENT AND HESSIAN ACCORDINGLY  ***
+C
+      IPI = IV(PERM)
+      CALL DS7IPR(N, IV(IPI), H)
+      CALL DV7IPR(N, IV(IPI), V(DG1))
+      V(DGNORM) = ZERO
+      IF (IV(NC) .GT. 0) V(DGNORM) = DV2NRM(IV(NC), V(DG1))
+C
+      IF (IV(CNVCOD) .NE. 0) GO TO 430
+      IF (IV(MODE) .EQ. 0) GO TO 380
+C
+C  ***  ALLOW FIRST STEP TO HAVE SCALED 2-NORM AT MOST V(LMAX0)  ***
+C
+      V(RADIUS) = V(LMAX0) / (ONE + V(PHMXFC))
+C
+      IV(MODE) = 0
+C
+C
+C-----------------------------  MAIN LOOP  -----------------------------
+C
+C
+C  ***  PRINT ITERATION SUMMARY, CHECK ITERATION LIMIT  ***
+C
+ 140  CALL DITSUM(D, G, IV, LIV, LV, N, V, X)
+ 150  K = IV(NITER)
+      IF (K .LT. IV(MXITER)) GO TO 160
+         IV(1) = 10
+         GO TO 440
+C
+ 160  IV(NITER) = K + 1
+C
+C  ***  INITIALIZE FOR START OF NEXT ITERATION  ***
+C
+      X01 = IV(X0)
+      V(F0) = V(F)
+      IV(IRC) = 4
+      IV(KAGQT) = -1
+C
+C     ***  COPY X TO X0  ***
+C
+      CALL DV7CPY(N, V(X01), X)
+C
+C  ***  UPDATE RADIUS  ***
+C
+      IF (K .EQ. 0) GO TO 180
+      STEP1 = IV(STEP)
+      K = STEP1
+      DO 170 I = 1, N
+         V(K) = D(I) * V(K)
+         K = K + 1
+ 170     CONTINUE
+      T = V(RADFAC) * DV2NRM(N, V(STEP1))
+      IF (V(RADFAC) .LT. ONE .OR. T .GT. V(RADIUS)) V(RADIUS) = T
+C
+C  ***  CHECK STOPX AND FUNCTION EVALUATION LIMIT  ***
+C
+ 180  IF (.NOT. STOPX(DUMMY)) GO TO 200
+         IV(1) = 11
+         GO TO 210
+C
+C     ***  COME HERE WHEN RESTARTING AFTER FUNC. EVAL. LIMIT OR STOPX.
+C
+ 190  IF (V(F) .GE. V(F0)) GO TO 200
+         V(RADFAC) = ONE
+         K = IV(NITER)
+         GO TO 160
+C
+ 200  IF (IV(NFCALL) .LT. IV(MXFCAL)) GO TO 220
+         IV(1) = 9
+ 210     IF (V(F) .GE. V(F0)) GO TO 440
+C
+C        ***  IN CASE OF STOPX OR FUNCTION EVALUATION LIMIT WITH
+C        ***  IMPROVED V(F), EVALUATE THE GRADIENT AT X.
+C
+              IV(CNVCOD) = IV(1)
+              GO TO 370
+C
+C. . . . . . . . . . . . .  COMPUTE CANDIDATE STEP  . . . . . . . . . .
+C
+ 220  STEP1 = IV(STEP)
+      L = IV(LMAT)
+      W1 = IV(W)
+      IPI = IV(PERM)
+      IPN = IPI + N
+      IPIV2 = IPN + N
+      TG1 = IV(DG)
+      TD1 = TG1 + N
+      X01 = IV(X0)
+      X11 = X01 + N
+      CALL DG7QSB(B, D, H, G, IV(IPI), IV(IPN), IV(IPIV2), IV(KAGQT),
+     1            V(L), LV, N, IV(N0), IV(NC), V(STEP1), V(TD1), V(TG1),
+     2            V, V(W1), V(X11), V(X01))
+      IF (IV(IRC) .NE. 6) GO TO 230
+         IF (IV(RESTOR) .NE. 2) GO TO 250
+         RSTRST = 2
+         GO TO 260
+C
+C  ***  CHECK WHETHER EVALUATING F(X0 + STEP) LOOKS WORTHWHILE  ***
+C
+ 230  IV(TOOBIG) = 0
+      IF (V(DSTNRM) .LE. ZERO) GO TO 250
+      IF (IV(IRC) .NE. 5) GO TO 240
+      IF (V(RADFAC) .LE. ONE) GO TO 240
+      IF (V(PREDUC) .GT. ONEP2 * V(FDIF)) GO TO 240
+         IF (IV(RESTOR) .NE. 2) GO TO 250
+         RSTRST = 0
+         GO TO 260
+C
+C  ***  COMPUTE F(X0 + STEP)  ***
+C
+ 240  CALL DV2AXY(N, X, ONE, V(STEP1), V(X01))
+      IV(NFCALL) = IV(NFCALL) + 1
+      IV(1) = 1
+      GO TO 450
+C
+C. . . . . . . . . . . . .  ASSESS CANDIDATE STEP  . . . . . . . . . . .
+C
+ 250  RSTRST = 3
+ 260  X01 = IV(X0)
+      V(RELDX) = DRLDST(N, D, X, V(X01))
+      CALL DA7SST(IV, LIV, LV, V)
+      STEP1 = IV(STEP)
+      LSTGST = STEP1 + 2*N
+      I = IV(RESTOR) + 1
+      GO TO (300, 270, 280, 290), I
+ 270  CALL DV7CPY(N, X, V(X01))
+      GO TO 300
+ 280   CALL DV7CPY(N, V(LSTGST), X)
+       GO TO 300
+ 290     CALL DV7CPY(N, X, V(LSTGST))
+         CALL DV2AXY(N, V(STEP1), NEGONE, V(X01), X)
+         V(RELDX) = DRLDST(N, D, X, V(X01))
+         IV(RESTOR) = RSTRST
+C
+ 300  K = IV(IRC)
+      GO TO (310,340,340,340,310,320,330,330,330,330,330,330,410,380), K
+C
+C     ***  RECOMPUTE STEP WITH NEW RADIUS  ***
+C
+ 310     V(RADIUS) = V(RADFAC) * V(DSTNRM)
+         GO TO 180
+C
+C  ***  COMPUTE STEP OF LENGTH V(LMAXS) FOR SINGULAR CONVERGENCE TEST.
+C
+ 320  V(RADIUS) = V(LMAXS)
+      GO TO 220
+C
+C  ***  CONVERGENCE OR FALSE CONVERGENCE  ***
+C
+ 330  IV(CNVCOD) = K - 4
+      IF (V(F) .GE. V(F0)) GO TO 430
+         IF (IV(XIRC) .EQ. 14) GO TO 430
+              IV(XIRC) = 14
+C
+C. . . . . . . . . . . .  PROCESS ACCEPTABLE STEP  . . . . . . . . . . .
+C
+ 340  IF (IV(IRC) .NE. 3) GO TO 370
+         TEMP1 = LSTGST
+C
+C     ***  PREPARE FOR GRADIENT TESTS  ***
+C     ***  SET  TEMP1 = HESSIAN * STEP + G(X0)
+C     ***             = DIAG(D) * (H * STEP + G(X0))
+C
+         K = TEMP1
+         STEP0 = STEP1 - 1
+         IPI = IV(PERM)
+         DO 350 I = 1, N
+              J = IV(IPI)
+              IPI = IPI + 1
+              STEP1 = STEP0 + J
+              V(K) = D(J) * V(STEP1)
+              K = K + 1
+ 350          CONTINUE
+C        USE X0 VECTOR AS TEMPORARY.
+         CALL DS7LVM(N, V(X01), H, V(TEMP1))
+         TEMP0 = TEMP1 - 1
+         IPI = IV(PERM)
+         DO 360 I = 1, N
+              J = IV(IPI)
+              IPI = IPI + 1
+              TEMP1 = TEMP0 + J
+              V(TEMP1) = D(J) * V(X01) + G(J)
+              X01 = X01 + 1
+ 360          CONTINUE
+C
+C  ***  COMPUTE GRADIENT AND HESSIAN  ***
+C
+ 370  IV(NGCALL) = IV(NGCALL) + 1
+      IV(TOOBIG) = 0
+      IV(1) = 2
+      GO TO 450
+C
+ 380  IV(1) = 2
+      IF (IV(IRC) .NE. 3) GO TO 140
+C
+C  ***  SET V(RADFAC) BY GRADIENT TESTS  ***
+C
+      STEP1 = IV(STEP)
+C     *** TEMP1 = STLSTG ***
+      TEMP1 = STEP1 + 2*N
+C
+C     ***  SET  TEMP1 = DIAG(D)**-1 * (HESSIAN*STEP + (G(X0)-G(X)))  ***
+C
+      K = TEMP1
+      DO 390 I = 1, N
+         V(K) = (V(K) - G(I)) / D(I)
+         K = K + 1
+ 390     CONTINUE
+C
+C     ***  DO GRADIENT TESTS  ***
+C
+      IF (DV2NRM(N, V(TEMP1)) .LE. V(DGNORM) * V(TUNER4)) GO TO 400
+           IF (DD7TPR(N, G, V(STEP1))
+     1               .GE. V(GTSTEP) * V(TUNER5))  GO TO 140
+ 400            V(RADFAC) = V(INCFAC)
+                GO TO 140
+C
+C. . . . . . . . . . . . . .  MISC. DETAILS  . . . . . . . . . . . . . .
+C
+C  ***  BAD PARAMETERS TO ASSESS  ***
+C
+ 410  IV(1) = 64
+      GO TO 440
+C
+C  ***  INCONSISTENT B  ***
+C
+ 420  IV(1) = 82
+      GO TO 440
+C
+C  ***  PRINT SUMMARY OF FINAL ITERATION AND OTHER REQUESTED ITEMS  ***
+C
+ 430  IV(1) = IV(CNVCOD)
+      IV(CNVCOD) = 0
+ 440  CALL DITSUM(D, G, IV, LIV, LV, N, V, X)
+      GO TO 999
+C
+C  ***  PROJECT X INTO FEASIBLE REGION (PRIOR TO COMPUTING F OR G)  ***
+C
+ 450  DO 460 I = 1, N
+         IF (X(I) .LT. B(1,I)) X(I) = B(1,I)
+         IF (X(I) .GT. B(2,I)) X(I) = B(2,I)
+ 460     CONTINUE
+C
+ 999  RETURN
+C
+C  ***  LAST CARD OF DRMNHB FOLLOWS  ***
+      END
+      SUBROUTINE DRMNH(D, FX, G, H, IV, LH, LIV, LV, N, V, X)
+C
+C  ***  CARRY OUT  DMNH (UNCONSTRAINED MINIMIZATION) ITERATIONS, USING
+C  ***  HESSIAN MATRIX PROVIDED BY THE CALLER.
+C
+C  ***  PARAMETER DECLARATIONS  ***
+C
+      INTEGER LH, LIV, LV, N
+      INTEGER IV(LIV)
+      DOUBLE PRECISION D(N), FX, G(N), H(LH), V(LV), X(N)
+C
+C--------------------------  PARAMETER USAGE  --------------------------
+C
+C D.... SCALE VECTOR.
+C FX... FUNCTION VALUE.
+C G.... GRADIENT VECTOR.
+C H.... LOWER TRIANGLE OF THE HESSIAN, STORED ROWWISE.
+C IV... INTEGER VALUE ARRAY.
+C LH... LENGTH OF H = P*(P+1)/2.
+C LIV.. LENGTH OF IV (AT LEAST 60).
+C LV... LENGTH OF V (AT LEAST 78 + N*(N+21)/2).
+C N.... NUMBER OF VARIABLES (COMPONENTS IN X AND G).
+C V.... FLOATING-POINT VALUE ARRAY.
+C X.... PARAMETER VECTOR.
+C
+C  ***  DISCUSSION  ***
+C
+C        PARAMETERS IV, N, V, AND X ARE THE SAME AS THE CORRESPONDING
+C     ONES TO  DMNH (WHICH SEE), EXCEPT THAT V CAN BE SHORTER (SINCE
+C     THE PART OF V THAT  DMNH USES FOR STORING G AND H IS NOT NEEDED).
+C     MOREOVER, COMPARED WITH  DMNH, IV(1) MAY HAVE THE TWO ADDITIONAL
+C     OUTPUT VALUES 1 AND 2, WHICH ARE EXPLAINED BELOW, AS IS THE USE
+C     OF IV(TOOBIG) AND IV(NFGCAL).  THE VALUE IV(G), WHICH IS AN
+C     OUTPUT VALUE FROM  DMNH, IS NOT REFERENCED BY DRMNH OR THE
+C     SUBROUTINES IT CALLS.
+C
+C IV(1) = 1 MEANS THE CALLER SHOULD SET FX TO F(X), THE FUNCTION VALUE
+C             AT X, AND CALL DRMNH AGAIN, HAVING CHANGED NONE OF THE
+C             OTHER PARAMETERS.  AN EXCEPTION OCCURS IF F(X) CANNOT BE
+C             COMPUTED (E.G. IF OVERFLOW WOULD OCCUR), WHICH MAY HAPPEN
+C             BECAUSE OF AN OVERSIZED STEP.  IN THIS CASE THE CALLER
+C             SHOULD SET IV(TOOBIG) = IV(2) TO 1, WHICH WILL CAUSE
+C             DRMNH TO IGNORE FX AND TRY A SMALLER STEP.  THE PARA-
+C             METER NF THAT  DMNH PASSES TO CALCF (FOR POSSIBLE USE BY
+C             CALCGH) IS A COPY OF IV(NFCALL) = IV(6).
+C IV(1) = 2 MEANS THE CALLER SHOULD SET G TO G(X), THE GRADIENT OF F AT
+C             X, AND H TO THE LOWER TRIANGLE OF H(X), THE HESSIAN OF F
+C             AT X, AND CALL DRMNH AGAIN, HAVING CHANGED NONE OF THE
+C             OTHER PARAMETERS EXCEPT PERHAPS THE SCALE VECTOR D.
+C                  THE PARAMETER NF THAT  DMNH PASSES TO CALCG IS
+C             IV(NFGCAL) = IV(7).  IF G(X) AND H(X) CANNOT BE EVALUATED,
+C             THEN THE CALLER MAY SET IV(TOOBIG) TO 0, IN WHICH CASE
+C             DRMNH WILL RETURN WITH IV(1) = 65.
+C                  NOTE -- DRMNH OVERWRITES H WITH THE LOWER TRIANGLE
+C             OF  DIAG(D)**-1 * H(X) * DIAG(D)**-1.
+C.
+C  ***  GENERAL  ***
+C
+C     CODED BY DAVID M. GAY (WINTER 1980).  REVISED SEPT. 1982.
+C     THIS SUBROUTINE WAS WRITTEN IN CONNECTION WITH RESEARCH SUPPORTED
+C     IN PART BY THE NATIONAL SCIENCE FOUNDATION UNDER GRANTS
+C     MCS-7600324 AND MCS-7906671.
+C
+C        (SEE  DMNG AND  DMNH FOR REFERENCES.)
+C
+C+++++++++++++++++++++++++++  DECLARATIONS  ++++++++++++++++++++++++++++
+C
+C  ***  LOCAL VARIABLES  ***
+C
+      INTEGER DG1, DUMMY, I, J, K, L, LSTGST, NN1O2, RSTRST, STEP1,
+     1        TEMP1, W1, X01
+      DOUBLE PRECISION T
+C
+C     ***  CONSTANTS  ***
+C
+      DOUBLE PRECISION ONE, ONEP2, ZERO
+C
+C  ***  NO INTRINSIC FUNCTIONS  ***
+C
+C  ***  EXTERNAL FUNCTIONS AND SUBROUTINES  ***
+C
+      LOGICAL STOPX
+      DOUBLE PRECISION DD7TPR, DRLDST, DV2NRM
+      EXTERNAL DA7SST,DIVSET, DD7TPR,DD7DUP,DG7QTS,DITSUM,DPARCK,
+     1         DRLDST, DS7LVM, STOPX,DV2AXY,DV7CPY, DV7SCP, DV2NRM
+C
+C DA7SST.... ASSESSES CANDIDATE STEP.
+C DIVSET.... PROVIDES DEFAULT IV AND V INPUT VALUES.
+C DD7TPR... RETURNS INNER PRODUCT OF TWO VECTORS.
+C DD7DUP.... UPDATES SCALE VECTOR D.
+C DG7QTS.... COMPUTES OPTIMALLY LOCALLY CONSTRAINED STEP.
+C DITSUM.... PRINTS ITERATION SUMMARY AND INFO ON INITIAL AND FINAL X.
+C DPARCK.... CHECKS VALIDITY OF INPUT IV AND V VALUES.
+C DRLDST... COMPUTES V(RELDX) = RELATIVE STEP SIZE.
+C DS7LVM... MULTIPLIES SYMMETRIC MATRIX TIMES VECTOR, GIVEN THE LOWER
+C             TRIANGLE OF THE MATRIX.
+C STOPX.... RETURNS .TRUE. IF THE BREAK KEY HAS BEEN PRESSED.
+C DV2AXY.... COMPUTES SCALAR TIMES ONE VECTOR PLUS ANOTHER.
+C DV7CPY.... COPIES ONE VECTOR TO ANOTHER.
+C DV7SCP... SETS ALL ELEMENTS OF A VECTOR TO A SCALAR.
+C DV2NRM... RETURNS THE 2-NORM OF A VECTOR.
+C
+C  ***  SUBSCRIPTS FOR IV AND V  ***
+C
+      INTEGER CNVCOD, DG, DGNORM, DINIT, DSTNRM, DTINIT, DTOL,
+     1        DTYPE, D0INIT, F, F0, FDIF, GTSTEP, INCFAC, IRC, KAGQT,
+     2        LMAT, LMAX0, LMAXS, MODE, MODEL, MXFCAL, MXITER, NEXTV,
+     3        NFCALL, NFGCAL, NGCALL, NITER, PHMXFC, PREDUC, RADFAC,
+     4        RADINC, RADIUS, RAD0, RELDX, RESTOR, STEP, STGLIM, STLSTG,
+     5        STPPAR, TOOBIG, TUNER4, TUNER5, VNEED, W, XIRC, X0
+C
+C  ***  IV SUBSCRIPT VALUES  ***
+C
+      PARAMETER (CNVCOD=55, DG=37, DTOL=59, DTYPE=16, IRC=29, KAGQT=33,
+     1           LMAT=42, MODE=35, MODEL=5, MXFCAL=17, MXITER=18,
+     2           NEXTV=47, NFCALL=6, NFGCAL=7, NGCALL=30, NITER=31,
+     3           RADINC=8, RESTOR=9, STEP=40, STGLIM=11, STLSTG=41,
+     4           TOOBIG=2, VNEED=4, W=34, XIRC=13, X0=43)
+C
+C  ***  V SUBSCRIPT VALUES  ***
+C
+      PARAMETER (DGNORM=1, DINIT=38, DSTNRM=2, DTINIT=39, D0INIT=40,
+     1           F=10, F0=13, FDIF=11, GTSTEP=4, INCFAC=23, LMAX0=35,
+     2           LMAXS=36, PHMXFC=21, PREDUC=7, RADFAC=16, RADIUS=8,
+     3           RAD0=9, RELDX=17, STPPAR=5, TUNER4=29, TUNER5=30)
+C
+      PARAMETER (ONE=1.D+0, ONEP2=1.2D+0, ZERO=0.D+0)
+C
+C+++++++++++++++++++++++++++++++  BODY  ++++++++++++++++++++++++++++++++
+C
+      I = IV(1)
+      IF (I .EQ. 1) GO TO 30
+      IF (I .EQ. 2) GO TO 40
+C
+C  ***  CHECK VALIDITY OF IV AND V INPUT VALUES  ***
+C
+      IF (IV(1) .EQ. 0) CALL DIVSET(2, IV, LIV, LV, V)
+      IF (IV(1) .EQ. 12 .OR. IV(1) .EQ. 13)
+     1     IV(VNEED) = IV(VNEED) + N*(N+21)/2 + 7
+      CALL DPARCK(2, D, IV, LIV, LV, N, V)
+      I = IV(1) - 2
+      IF (I .GT. 12) GO TO 999
+      NN1O2 = N * (N + 1) / 2
+      IF (LH .GE. NN1O2) GO TO (220,220,220,220,220,220,160,120,160,
+     1                          10,10,20), I
+         IV(1) = 66
+         GO TO 400
+C
+C  ***  STORAGE ALLOCATION  ***
+C
+ 10   IV(DTOL) = IV(LMAT) + NN1O2
+      IV(X0) = IV(DTOL) + 2*N
+      IV(STEP) = IV(X0) + N
+      IV(STLSTG) = IV(STEP) + N
+      IV(DG) = IV(STLSTG) + N
+      IV(W) = IV(DG) + N
+      IV(NEXTV) = IV(W) + 4*N + 7
+      IF (IV(1) .NE. 13) GO TO 20
+         IV(1) = 14
+         GO TO 999
+C
+C  ***  INITIALIZATION  ***
+C
+ 20   IV(NITER) = 0
+      IV(NFCALL) = 1
+      IV(NGCALL) = 1
+      IV(NFGCAL) = 1
+      IV(MODE) = -1
+      IV(MODEL) = 1
+      IV(STGLIM) = 1
+      IV(TOOBIG) = 0
+      IV(CNVCOD) = 0
+      IV(RADINC) = 0
+      V(RAD0) = ZERO
+      V(STPPAR) = ZERO
+      IF (V(DINIT) .GE. ZERO) CALL DV7SCP(N, D, V(DINIT))
+      K = IV(DTOL)
+      IF (V(DTINIT) .GT. ZERO) CALL DV7SCP(N, V(K), V(DTINIT))
+      K = K + N
+      IF (V(D0INIT) .GT. ZERO) CALL DV7SCP(N, V(K), V(D0INIT))
+      IV(1) = 1
+      GO TO 999
+C
+ 30   V(F) = FX
+      IF (IV(MODE) .GE. 0) GO TO 220
+      V(F0) = FX
+      IV(1) = 2
+      IF (IV(TOOBIG) .EQ. 0) GO TO 999
+         IV(1) = 63
+         GO TO 400
+C
+C  ***  MAKE SURE GRADIENT COULD BE COMPUTED  ***
+C
+ 40   IF (IV(TOOBIG) .EQ. 0) GO TO 50
+         IV(1) = 65
+         GO TO 400
+C
+C  ***  UPDATE THE SCALE VECTOR D  ***
+C
+ 50   DG1 = IV(DG)
+      IF (IV(DTYPE) .LE. 0) GO TO 70
+      K = DG1
+      J = 0
+      DO 60 I = 1, N
+         J = J + I
+         V(K) = H(J)
+         K = K + 1
+ 60      CONTINUE
+      CALL DD7DUP(D, V(DG1), IV, LIV, LV, N, V)
+C
+C  ***  COMPUTE SCALED GRADIENT AND ITS NORM  ***
+C
+ 70   DG1 = IV(DG)
+      K = DG1
+      DO 80 I = 1, N
+         V(K) = G(I) / D(I)
+         K = K + 1
+ 80      CONTINUE
+      V(DGNORM) = DV2NRM(N, V(DG1))
+C
+C  ***  COMPUTE SCALED HESSIAN  ***
+C
+      K = 1
+      DO 100 I = 1, N
+         T = ONE / D(I)
+         DO 90 J = 1, I
+              H(K) = T * H(K) / D(J)
+              K = K + 1
+ 90           CONTINUE
+ 100     CONTINUE
+C
+      IF (IV(CNVCOD) .NE. 0) GO TO 390
+      IF (IV(MODE) .EQ. 0) GO TO 350
+C
+C  ***  ALLOW FIRST STEP TO HAVE SCALED 2-NORM AT MOST V(LMAX0)  ***
+C
+      V(RADIUS) = V(LMAX0) / (ONE + V(PHMXFC))
+C
+      IV(MODE) = 0
+C
+C
+C-----------------------------  MAIN LOOP  -----------------------------
+C
+C
+C  ***  PRINT ITERATION SUMMARY, CHECK ITERATION LIMIT  ***
+C
+ 110  CALL DITSUM(D, G, IV, LIV, LV, N, V, X)
+ 120  K = IV(NITER)
+      IF (K .LT. IV(MXITER)) GO TO 130
+         IV(1) = 10
+         GO TO 400
+C
+ 130  IV(NITER) = K + 1
+C
+C  ***  INITIALIZE FOR START OF NEXT ITERATION  ***
+C
+      DG1 = IV(DG)
+      X01 = IV(X0)
+      V(F0) = V(F)
+      IV(IRC) = 4
+      IV(KAGQT) = -1
+C
+C     ***  COPY X TO X0  ***
+C
+      CALL DV7CPY(N, V(X01), X)
+C
+C  ***  UPDATE RADIUS  ***
+C
+      IF (K .EQ. 0) GO TO 150
+      STEP1 = IV(STEP)
+      K = STEP1
+      DO 140 I = 1, N
+         V(K) = D(I) * V(K)
+         K = K + 1
+ 140     CONTINUE
+      V(RADIUS) = V(RADFAC) * DV2NRM(N, V(STEP1))
+C
+C  ***  CHECK STOPX AND FUNCTION EVALUATION LIMIT  ***
+C
+ 150  IF (.NOT. STOPX(DUMMY)) GO TO 170
+         IV(1) = 11
+         GO TO 180
+C
+C     ***  COME HERE WHEN RESTARTING AFTER FUNC. EVAL. LIMIT OR STOPX.
+C
+ 160  IF (V(F) .GE. V(F0)) GO TO 170
+         V(RADFAC) = ONE
+         K = IV(NITER)
+         GO TO 130
+C
+ 170  IF (IV(NFCALL) .LT. IV(MXFCAL)) GO TO 190
+         IV(1) = 9
+ 180     IF (V(F) .GE. V(F0)) GO TO 400
+C
+C        ***  IN CASE OF STOPX OR FUNCTION EVALUATION LIMIT WITH
+C        ***  IMPROVED V(F), EVALUATE THE GRADIENT AT X.
+C
+              IV(CNVCOD) = IV(1)
+              GO TO 340
+C
+C. . . . . . . . . . . . .  COMPUTE CANDIDATE STEP  . . . . . . . . . .
+C
+ 190  STEP1 = IV(STEP)
+      DG1 = IV(DG)
+      L = IV(LMAT)
+      W1 = IV(W)
+      CALL DG7QTS(D, V(DG1), H, IV(KAGQT), V(L), N, V(STEP1), V, V(W1))
+      IF (IV(IRC) .NE. 6) GO TO 200
+         IF (IV(RESTOR) .NE. 2) GO TO 220
+         RSTRST = 2
+         GO TO 230
+C
+C  ***  CHECK WHETHER EVALUATING F(X0 + STEP) LOOKS WORTHWHILE  ***
+C
+ 200  IV(TOOBIG) = 0
+      IF (V(DSTNRM) .LE. ZERO) GO TO 220
+      IF (IV(IRC) .NE. 5) GO TO 210
+      IF (V(RADFAC) .LE. ONE) GO TO 210
+      IF (V(PREDUC) .GT. ONEP2 * V(FDIF)) GO TO 210
+         IF (IV(RESTOR) .NE. 2) GO TO 220
+         RSTRST = 0
+         GO TO 230
+C
+C  ***  COMPUTE F(X0 + STEP)  ***
+C
+ 210  X01 = IV(X0)
+      STEP1 = IV(STEP)
+      CALL DV2AXY(N, X, ONE, V(STEP1), V(X01))
+      IV(NFCALL) = IV(NFCALL) + 1
+      IV(1) = 1
+      GO TO 999
+C
+C. . . . . . . . . . . . .  ASSESS CANDIDATE STEP  . . . . . . . . . . .
+C
+ 220  RSTRST = 3
+ 230  X01 = IV(X0)
+      V(RELDX) = DRLDST(N, D, X, V(X01))
+      CALL DA7SST(IV, LIV, LV, V)
+      STEP1 = IV(STEP)
+      LSTGST = IV(STLSTG)
+      I = IV(RESTOR) + 1
+      GO TO (270, 240, 250, 260), I
+ 240  CALL DV7CPY(N, X, V(X01))
+      GO TO 270
+ 250   CALL DV7CPY(N, V(LSTGST), V(STEP1))
+       GO TO 270
+ 260     CALL DV7CPY(N, V(STEP1), V(LSTGST))
+         CALL DV2AXY(N, X, ONE, V(STEP1), V(X01))
+         V(RELDX) = DRLDST(N, D, X, V(X01))
+         IV(RESTOR) = RSTRST
+C
+ 270  K = IV(IRC)
+      GO TO (280,310,310,310,280,290,300,300,300,300,300,300,380,350), K
+C
+C     ***  RECOMPUTE STEP WITH NEW RADIUS  ***
+C
+ 280     V(RADIUS) = V(RADFAC) * V(DSTNRM)
+         GO TO 150
+C
+C  ***  COMPUTE STEP OF LENGTH V(LMAXS) FOR SINGULAR CONVERGENCE TEST.
+C
+ 290  V(RADIUS) = V(LMAXS)
+      GO TO 190
+C
+C  ***  CONVERGENCE OR FALSE CONVERGENCE  ***
+C
+ 300  IV(CNVCOD) = K - 4
+      IF (V(F) .GE. V(F0)) GO TO 390
+         IF (IV(XIRC) .EQ. 14) GO TO 390
+              IV(XIRC) = 14
+C
+C. . . . . . . . . . . .  PROCESS ACCEPTABLE STEP  . . . . . . . . . . .
+C
+ 310  IF (IV(IRC) .NE. 3) GO TO 340
+         TEMP1 = LSTGST
+C
+C     ***  PREPARE FOR GRADIENT TESTS  ***
+C     ***  SET  TEMP1 = HESSIAN * STEP + G(X0)
+C     ***             = DIAG(D) * (H * STEP + G(X0))
+C
+C        USE X0 VECTOR AS TEMPORARY.
+         K = X01
+         DO 320 I = 1, N
+              V(K) = D(I) * V(STEP1)
+              K = K + 1
+              STEP1 = STEP1 + 1
+ 320          CONTINUE
+         CALL DS7LVM(N, V(TEMP1), H, V(X01))
+         DO 330 I = 1, N
+              V(TEMP1) = D(I) * V(TEMP1) + G(I)
+              TEMP1 = TEMP1 + 1
+ 330          CONTINUE
+C
+C  ***  COMPUTE GRADIENT AND HESSIAN  ***
+C
+ 340  IV(NGCALL) = IV(NGCALL) + 1
+      IV(TOOBIG) = 0
+      IV(1) = 2
+      GO TO 999
+C
+ 350  IV(1) = 2
+      IF (IV(IRC) .NE. 3) GO TO 110
+C
+C  ***  SET V(RADFAC) BY GRADIENT TESTS  ***
+C
+      TEMP1 = IV(STLSTG)
+      STEP1 = IV(STEP)
+C
+C     ***  SET  TEMP1 = DIAG(D)**-1 * (HESSIAN*STEP + (G(X0)-G(X)))  ***
+C
+      K = TEMP1
+      DO 360 I = 1, N
+         V(K) = (V(K) - G(I)) / D(I)
+         K = K + 1
+ 360     CONTINUE
+C
+C     ***  DO GRADIENT TESTS  ***
+C
+      IF (DV2NRM(N, V(TEMP1)) .LE. V(DGNORM) * V(TUNER4)) GO TO 370
+           IF (DD7TPR(N, G, V(STEP1))
+     1               .GE. V(GTSTEP) * V(TUNER5))  GO TO 110
+ 370            V(RADFAC) = V(INCFAC)
+                GO TO 110
+C
+C. . . . . . . . . . . . . .  MISC. DETAILS  . . . . . . . . . . . . . .
+C
+C  ***  BAD PARAMETERS TO ASSESS  ***
+C
+ 380  IV(1) = 64
+      GO TO 400
+C
+C  ***  PRINT SUMMARY OF FINAL ITERATION AND OTHER REQUESTED ITEMS  ***
+C
+ 390  IV(1) = IV(CNVCOD)
+      IV(CNVCOD) = 0
+ 400  CALL DITSUM(D, G, IV, LIV, LV, N, V, X)
+C
+ 999  RETURN
+C
+C  ***  LAST CARD OF DRMNH FOLLOWS  ***
+      END
+      SUBROUTINE DQ7RSH(K, P, HAVQTR, QTR, R, W)
+C
+C  ***  PERMUTE COLUMN K OF R TO COLUMN P, MODIFY QTR ACCORDINGLY  ***
+C
+      LOGICAL HAVQTR
+      INTEGER K, P
+      DOUBLE PRECISION QTR(P), R(*), W(P)
+C     DIMENSION R(P*(P+1)/2)
+C
+      DOUBLE PRECISION DH2RFG
+      EXTERNAL DH2RFA, DH2RFG,DV7CPY
+C
+C  ***  LOCAL VARIABLES  ***
+C
+      INTEGER I, I1, J, JM1, JP1, J1, KM1, K1, PM1
+      DOUBLE PRECISION A, B, T, WJ, X, Y, Z, ZERO
+C
+      DATA ZERO/0.0D+0/
+C
+C+++++++++++++++++++++++++++++++  BODY  ++++++++++++++++++++++++++++++++
+C
+      IF (K .GE. P) GO TO 999
+      KM1 = K - 1
+      K1 = K * KM1 / 2
+      CALL DV7CPY(K, W, R(K1+1))
+      WJ = W(K)
+      PM1 = P - 1
+      J1 = K1 + KM1
+      DO 50 J = K, PM1
+         JM1 = J - 1
+         JP1 = J + 1
+         IF (JM1 .GT. 0) CALL DV7CPY(JM1, R(K1+1), R(J1+2))
+         J1 = J1 + JP1
+         K1 = K1 + J
+         A = R(J1)
+         B = R(J1+1)
+         IF (B .NE. ZERO) GO TO 10
+              R(K1) = A
+              X = ZERO
+              Z = ZERO
+              GO TO 40
+ 10      R(K1) = DH2RFG(A, B, X, Y, Z)
+         IF (J .EQ. PM1) GO TO 30
+         I1 = J1
+         DO 20 I = JP1, PM1
+              I1 = I1 + I
+              CALL DH2RFA(1, R(I1), R(I1+1), X, Y, Z)
+ 20           CONTINUE
+ 30      IF (HAVQTR) CALL DH2RFA(1, QTR(J), QTR(JP1), X, Y, Z)
+ 40      T = X * WJ
+         W(J) = WJ + T
+         WJ = T * Z
+ 50      CONTINUE
+      W(P) = WJ
+      CALL DV7CPY(P, R(K1+1), W)
+ 999  RETURN
+      END
+      SUBROUTINE DRMNF(D, FX, IV, LIV, LV, N, V, X)
+C
+C  ***  ITERATION DRIVER FOR  DMNF...
+C  ***  MINIMIZE GENERAL UNCONSTRAINED OBJECTIVE FUNCTION USING
+C  ***  FINITE-DIFFERENCE GRADIENTS AND SECANT HESSIAN APPROXIMATIONS.
+C
+      INTEGER LIV, LV, N
+      INTEGER IV(LIV)
+      DOUBLE PRECISION D(N), FX, X(N), V(LV)
+C     DIMENSION V(77 + N*(N+17)/2)
+C
+C  ***  PURPOSE  ***
+C
+C        THIS ROUTINE INTERACTS WITH SUBROUTINE  DRMNG  IN AN ATTEMPT
+C     TO FIND AN N-VECTOR  X*  THAT MINIMIZES THE (UNCONSTRAINED)
+C     OBJECTIVE FUNCTION  FX = F(X)  COMPUTED BY THE CALLER.  (OFTEN
+C     THE  X*  FOUND IS A LOCAL MINIMIZER RATHER THAN A GLOBAL ONE.)
+C
+C  ***  PARAMETERS  ***
+C
+C        THE PARAMETERS FOR DRMNF ARE THE SAME AS THOSE FOR  DMNG
+C     (WHICH SEE), EXCEPT THAT CALCF, CALCG, UIPARM, URPARM, AND UFPARM
+C     ARE OMITTED, AND A PARAMETER  FX  FOR THE OBJECTIVE FUNCTION
+C     VALUE AT X IS ADDED.  INSTEAD OF CALLING CALCG TO OBTAIN THE
+C     GRADIENT OF THE OBJECTIVE FUNCTION AT X, DRMNF CALLS DS7GRD,
+C     WHICH COMPUTES AN APPROXIMATION TO THE GRADIENT BY FINITE
+C     (FORWARD AND CENTRAL) DIFFERENCES USING THE METHOD OF REF. 1.
+C     THE FOLLOWING INPUT COMPONENT IS OF INTEREST IN THIS REGARD
+C     (AND IS NOT DESCRIBED IN  DMNG).
+C
+C V(ETA0)..... V(42) IS AN ESTIMATED BOUND ON THE RELATIVE ERROR IN THE
+C             OBJECTIVE FUNCTION VALUE COMPUTED BY CALCF...
+C                  (TRUE VALUE) = (COMPUTED VALUE) * (1 + E),
+C             WHERE ABS(E) .LE. V(ETA0).  DEFAULT = MACHEP * 10**3,
+C             WHERE MACHEP IS THE UNIT ROUNDOFF.
+C
+C        THE OUTPUT VALUES IV(NFCALL) AND IV(NGCALL) HAVE DIFFERENT
+C     MEANINGS FOR  DMNF THAN FOR  DMNG...
+C
+C IV(NFCALL)... IV(6) IS THE NUMBER OF CALLS SO FAR MADE ON CALCF (I.E.,
+C             FUNCTION EVALUATIONS) EXCLUDING THOSE MADE ONLY FOR
+C             COMPUTING GRADIENTS.  THE INPUT VALUE IV(MXFCAL) IS A
+C             LIMIT ON IV(NFCALL).
+C IV(NGCALL)... IV(30) IS THE NUMBER OF FUNCTION EVALUATIONS MADE ONLY
+C             FOR COMPUTING GRADIENTS.  THE TOTAL NUMBER OF FUNCTION
+C             EVALUATIONS IS THUS  IV(NFCALL) + IV(NGCALL).
+C
+C  ***  REFERENCES  ***
+C
+C 1. STEWART, G.W. (1967), A MODIFICATION OF DAVIDON*S MINIMIZATION
+C        METHOD TO ACCEPT DIFFERENCE APPROXIMATIONS OF DERIVATIVES,
+C        J. ASSOC. COMPUT. MACH. 14, PP. 72-83.
+C.
+C  ***  GENERAL  ***
+C
+C     CODED BY DAVID M. GAY (AUGUST 1982).
+C
+C----------------------------  DECLARATIONS  ---------------------------
+C
+      DOUBLE PRECISION DD7TPR
+      EXTERNAL DIVSET, DD7TPR, DS7GRD, DRMNG, DV7SCP
+C
+C DIVSET.... SUPPLIES DEFAULT PARAMETER VALUES.
+C DD7TPR... RETURNS INNER PRODUCT OF TWO VECTORS.
+C DS7GRD... COMPUTES FINITE-DIFFERENCE GRADIENT APPROXIMATION.
+C DRMNG.... REVERSE-COMMUNICATION ROUTINE THAT DOES  DMNG ALGORITHM.
+C DV7SCP... SETS ALL ELEMENTS OF A VECTOR TO A SCALAR.
+C
+      INTEGER ALPHA, G1, I, IV1, J, K, W
+      DOUBLE PRECISION ZERO
+C
+C  ***  SUBSCRIPTS FOR IV   ***
+C
+      INTEGER ETA0, F, G, LMAT, NEXTV, NGCALL, NITER, SGIRC, TOOBIG,
+     1        VNEED
+C
+      PARAMETER (ETA0=42, F=10, G=28, LMAT=42, NEXTV=47, NGCALL=30,
+     1           NITER=31, SGIRC=57, TOOBIG=2, VNEED=4)
+      PARAMETER (ZERO=0.D+0)
+C
+C+++++++++++++++++++++++++++++++  BODY  ++++++++++++++++++++++++++++++++
+C
+      IV1 = IV(1)
+      IF (IV1 .EQ. 1) GO TO 10
+      IF (IV1 .EQ. 2) GO TO 50
+      IF (IV(1) .EQ. 0) CALL DIVSET(2, IV, LIV, LV, V)
+      IV1 = IV(1)
+      IF (IV1 .EQ. 12 .OR. IV1 .EQ. 13) IV(VNEED) = IV(VNEED) + 2*N + 6
+      IF (IV1 .EQ. 14) GO TO 10
+      IF (IV1 .GT. 2 .AND. IV1 .LT. 12) GO TO 10
+      G1 = 1
+      IF (IV1 .EQ. 12) IV(1) = 13
+      GO TO 20
+C
+ 10   G1 = IV(G)
+C
+ 20   CALL DRMNG(D, FX, V(G1), IV, LIV, LV, N, V, X)
+      IF (IV(1) .LT. 2) GO TO 999
+      IF (IV(1) .GT. 2) GO TO 70
+C
+C  ***  COMPUTE GRADIENT  ***
+C
+      IF (IV(NITER) .EQ. 0) CALL DV7SCP(N, V(G1), ZERO)
+      J = IV(LMAT)
+      K = G1 - N
+      DO 40 I = 1, N
+         V(K) = DD7TPR(I, V(J), V(J))
+         K = K + 1
+         J = J + I
+ 40      CONTINUE
+C     ***  UNDO INCREMENT OF IV(NGCALL) DONE BY DRMNG  ***
+      IV(NGCALL) = IV(NGCALL) - 1
+C     ***  STORE RETURN CODE FROM DS7GRD IN IV(SGIRC)  ***
+      IV(SGIRC) = 0
+C     ***  X MAY HAVE BEEN RESTORED, SO COPY BACK FX... ***
+      FX = V(F)
+      GO TO 60
+C
+C     ***  GRADIENT LOOP  ***
+C
+ 50   IF (IV(TOOBIG) .NE. 0) GO TO 10
+C
+ 60   G1 = IV(G)
+      ALPHA = G1 - N
+      W = ALPHA - 6
+      CALL DS7GRD(V(ALPHA), D, V(ETA0), FX, V(G1), IV(SGIRC), N, V(W),X)
+      IF (IV(SGIRC) .EQ. 0) GO TO 10
+         IV(NGCALL) = IV(NGCALL) + 1
+         GO TO 999
+C
+ 70   IF (IV(1) .NE. 14) GO TO 999
+C
+C  ***  STORAGE ALLOCATION  ***
+C
+      IV(G) = IV(NEXTV) + N + 6
+      IV(NEXTV) = IV(G) + N
+      IF (IV1 .NE. 13) GO TO 10
+C
+ 999  RETURN
+C  ***  LAST CARD OF DRMNF FOLLOWS  ***
+      END
+      SUBROUTINE DL7VML(N, X, L, Y)
+C
+C  ***  COMPUTE  X = L*Y, WHERE  L  IS AN  N X N  LOWER TRIANGULAR
+C  ***  MATRIX STORED COMPACTLY BY ROWS.  X AND Y MAY OCCUPY THE SAME
+C  ***  STORAGE.  ***
+C
+      INTEGER N
+      DOUBLE PRECISION X(N), L(*), Y(N)
+C     DIMENSION L(N*(N+1)/2)
+      INTEGER I, II, IJ, I0, J, NP1
+      DOUBLE PRECISION T, ZERO
+      PARAMETER (ZERO=0.D+0)
+C
+      NP1 = N + 1
+      I0 = N*(N+1)/2
+      DO 20 II = 1, N
+         I = NP1 - II
+         I0 = I0 - I
+         T = ZERO
+         DO 10 J = 1, I
+              IJ = I0 + J
+              T = T + L(IJ)*Y(J)
+ 10           CONTINUE
+         X(I) = T
+ 20      CONTINUE
+      RETURN
+C  ***  LAST CARD OF DL7VML FOLLOWS  ***
+      END
+      SUBROUTINE DA7SST(IV, LIV, LV, V)
+C
+C  ***  ASSESS CANDIDATE STEP (***SOL VERSION 2.3)  ***
+C
+      INTEGER LIV, LV
+      INTEGER IV(LIV)
+      DOUBLE PRECISION V(LV)
+C
+C  ***  PURPOSE  ***
+C
+C        THIS SUBROUTINE IS CALLED BY AN UNCONSTRAINED MINIMIZATION
+C     ROUTINE TO ASSESS THE NEXT CANDIDATE STEP.  IT MAY RECOMMEND ONE
+C     OF SEVERAL COURSES OF ACTION, SUCH AS ACCEPTING THE STEP, RECOM-
+C     PUTING IT USING THE SAME OR A NEW QUADRATIC MODEL, OR HALTING DUE
+C     TO CONVERGENCE OR FALSE CONVERGENCE.  SEE THE RETURN CODE LISTING
+C     BELOW.
+C
+C--------------------------  PARAMETER USAGE  --------------------------
+C
+C  IV (I/O) INTEGER PARAMETER AND SCRATCH VECTOR -- SEE DESCRIPTION
+C             BELOW OF IV VALUES REFERENCED.
+C LIV (IN)  LENGTH OF IV ARRAY.
+C  LV (IN)  LENGTH OF V ARRAY.
+C   V (I/O) REAL PARAMETER AND SCRATCH VECTOR -- SEE DESCRIPTION
+C             BELOW OF V VALUES REFERENCED.
+C
+C  ***  IV VALUES REFERENCED  ***
+C
+C    IV(IRC) (I/O) ON INPUT FOR THE FIRST STEP TRIED IN A NEW ITERATION,
+C             IV(IRC) SHOULD BE SET TO 3 OR 4 (THE VALUE TO WHICH IT IS
+C             SET WHEN STEP IS DEFINITELY TO BE ACCEPTED).  ON INPUT
+C             AFTER STEP HAS BEEN RECOMPUTED, IV(IRC) SHOULD BE
+C             UNCHANGED SINCE THE PREVIOUS RETURN OF DA7SST.
+C                ON OUTPUT, IV(IRC) IS A RETURN CODE HAVING ONE OF THE
+C             FOLLOWING VALUES...
+C                  1 = SWITCH MODELS OR TRY SMALLER STEP.
+C                  2 = SWITCH MODELS OR ACCEPT STEP.
+C                  3 = ACCEPT STEP AND DETERMINE V(RADFAC) BY GRADIENT
+C                       TESTS.
+C                  4 = ACCEPT STEP, V(RADFAC) HAS BEEN DETERMINED.
+C                  5 = RECOMPUTE STEP (USING THE SAME MODEL).
+C                  6 = RECOMPUTE STEP WITH RADIUS = V(LMAXS) BUT DO NOT
+C                       EVALUATE THE OBJECTIVE FUNCTION.
+C                  7 = X-CONVERGENCE (SEE V(XCTOL)).
+C                  8 = RELATIVE FUNCTION CONVERGENCE (SEE V(RFCTOL)).
+C                  9 = BOTH X- AND RELATIVE FUNCTION CONVERGENCE.
+C                 10 = ABSOLUTE FUNCTION CONVERGENCE (SEE V(AFCTOL)).
+C                 11 = SINGULAR CONVERGENCE (SEE V(LMAXS)).
+C                 12 = FALSE CONVERGENCE (SEE V(XFTOL)).
+C                 13 = IV(IRC) WAS OUT OF RANGE ON INPUT.
+C             RETURN CODE I HAS PRECEDENCE OVER I+1 FOR I = 9, 10, 11.
+C IV(MLSTGD) (I/O) SAVED VALUE OF IV(MODEL).
+C  IV(MODEL) (I/O) ON INPUT, IV(MODEL) SHOULD BE AN INTEGER IDENTIFYING
+C             THE CURRENT QUADRATIC MODEL OF THE OBJECTIVE FUNCTION.
+C             IF A PREVIOUS STEP YIELDED A BETTER FUNCTION REDUCTION,
+C             THEN IV(MODEL) WILL BE SET TO IV(MLSTGD) ON OUTPUT.
+C IV(NFCALL) (IN)  INVOCATION COUNT FOR THE OBJECTIVE FUNCTION.
+C IV(NFGCAL) (I/O) VALUE OF IV(NFCALL) AT STEP THAT GAVE THE BIGGEST
+C             FUNCTION REDUCTION THIS ITERATION.  IV(NFGCAL) REMAINS
+C             UNCHANGED UNTIL A FUNCTION REDUCTION IS OBTAINED.
+C IV(RADINC) (I/O) THE NUMBER OF RADIUS INCREASES (OR MINUS THE NUMBER
+C             OF DECREASES) SO FAR THIS ITERATION.
+C IV(RESTOR) (OUT) SET TO 1 IF V(F) HAS BEEN RESTORED AND X SHOULD BE
+C             RESTORED TO ITS INITIAL VALUE, TO 2 IF X SHOULD BE SAVED,
+C             TO 3 IF X SHOULD BE RESTORED FROM THE SAVED VALUE, AND TO
+C             0 OTHERWISE.
+C  IV(STAGE) (I/O) COUNT OF THE NUMBER OF MODELS TRIED SO FAR IN THE
+C             CURRENT ITERATION.
+C IV(STGLIM) (IN)  MAXIMUM NUMBER OF MODELS TO CONSIDER.
+C IV(SWITCH) (OUT) SET TO 0 UNLESS A NEW MODEL IS BEING TRIED AND IT
+C             GIVES A SMALLER FUNCTION VALUE THAN THE PREVIOUS MODEL,
+C             IN WHICH CASE DA7SST SETS IV(SWITCH) = 1.
+C IV(TOOBIG) (I/O)  IS NONZERO ON INPUT IF STEP WAS TOO BIG (E.G., IF
+C             IT WOULD CAUSE OVERFLOW).  IT IS SET TO 0 ON RETURN.
+C   IV(XIRC) (I/O) VALUE THAT IV(IRC) WOULD HAVE IN THE ABSENCE OF
+C             CONVERGENCE, FALSE CONVERGENCE, AND OVERSIZED STEPS.
+C
+C  ***  V VALUES REFERENCED  ***
+C
+C V(AFCTOL) (IN)  ABSOLUTE FUNCTION CONVERGENCE TOLERANCE.  IF THE
+C             ABSOLUTE VALUE OF THE CURRENT FUNCTION VALUE V(F) IS LESS
+C             THAN V(AFCTOL) AND DA7SST DOES NOT RETURN WITH
+C             IV(IRC) = 11, THEN DA7SST RETURNS WITH IV(IRC) = 10.
+C V(DECFAC) (IN)  FACTOR BY WHICH TO DECREASE RADIUS WHEN IV(TOOBIG) IS
+C             NONZERO.
+C V(DSTNRM) (IN)  THE 2-NORM OF D*STEP.
+C V(DSTSAV) (I/O) VALUE OF V(DSTNRM) ON SAVED STEP.
+C   V(DST0) (IN)  THE 2-NORM OF D TIMES THE NEWTON STEP (WHEN DEFINED,
+C             I.E., FOR V(NREDUC) .GE. 0).
+C      V(F) (I/O) ON BOTH INPUT AND OUTPUT, V(F) IS THE OBJECTIVE FUNC-
+C             TION VALUE AT X.  IF X IS RESTORED TO A PREVIOUS VALUE,
+C             THEN V(F) IS RESTORED TO THE CORRESPONDING VALUE.
+C   V(FDIF) (OUT) THE FUNCTION REDUCTION V(F0) - V(F) (FOR THE OUTPUT
+C             VALUE OF V(F) IF AN EARLIER STEP GAVE A BIGGER FUNCTION
+C             DECREASE, AND FOR THE INPUT VALUE OF V(F) OTHERWISE).
+C V(FLSTGD) (I/O) SAVED VALUE OF V(F).
+C     V(F0) (IN)  OBJECTIVE FUNCTION VALUE AT START OF ITERATION.
+C V(GTSLST) (I/O) VALUE OF V(GTSTEP) ON SAVED STEP.
+C V(GTSTEP) (IN)  INNER PRODUCT BETWEEN STEP AND GRADIENT.
+C V(INCFAC) (IN)  MINIMUM FACTOR BY WHICH TO INCREASE RADIUS.
+C  V(LMAXS) (IN)  MAXIMUM REASONABLE STEP SIZE (AND INITIAL STEP BOUND).
+C             IF THE ACTUAL FUNCTION DECREASE IS NO MORE THAN TWICE
+C             WHAT WAS PREDICTED, IF A RETURN WITH IV(IRC) = 7, 8, OR 9
+C             DOES NOT OCCUR, IF V(DSTNRM) .GT. V(LMAXS) OR THE CURRENT
+C             STEP IS A NEWTON STEP, AND IF
+C             V(PREDUC) .LE. V(SCTOL) * ABS(V(F0)), THEN DA7SST RETURNS
+C             WITH IV(IRC) = 11.  IF SO DOING APPEARS WORTHWHILE, THEN
+C            DA7SST REPEATS THIS TEST (DISALLOWING A FULL NEWTON STEP)
+C             WITH V(PREDUC) COMPUTED FOR A STEP OF LENGTH V(LMAXS)
+C             (BY A RETURN WITH IV(IRC) = 6).
+C V(NREDUC) (I/O)  FUNCTION REDUCTION PREDICTED BY QUADRATIC MODEL FOR
+C             NEWTON STEP.  IF DA7SST IS CALLED WITH IV(IRC) = 6, I.E.,
+C             IF V(PREDUC) HAS BEEN COMPUTED WITH RADIUS = V(LMAXS) FOR
+C             USE IN THE SINGULAR CONVERGENCE TEST, THEN V(NREDUC) IS
+C             SET TO -V(PREDUC) BEFORE THE LATTER IS RESTORED.
+C V(PLSTGD) (I/O) VALUE OF V(PREDUC) ON SAVED STEP.
+C V(PREDUC) (I/O) FUNCTION REDUCTION PREDICTED BY QUADRATIC MODEL FOR
+C             CURRENT STEP.
+C V(RADFAC) (OUT) FACTOR TO BE USED IN DETERMINING THE NEW RADIUS,
+C             WHICH SHOULD BE V(RADFAC)*DST, WHERE  DST  IS EITHER THE
+C             OUTPUT VALUE OF V(DSTNRM) OR THE 2-NORM OF
+C             DIAG(NEWD)*STEP  FOR THE OUTPUT VALUE OF STEP AND THE
+C             UPDATED VERSION, NEWD, OF THE SCALE VECTOR D.  FOR
+C             IV(IRC) = 3, V(RADFAC) = 1.0 IS RETURNED.
+C V(RDFCMN) (IN)  MINIMUM VALUE FOR V(RADFAC) IN TERMS OF THE INPUT
+C             VALUE OF V(DSTNRM) -- SUGGESTED VALUE = 0.1.
+C V(RDFCMX) (IN)  MAXIMUM VALUE FOR V(RADFAC) -- SUGGESTED VALUE = 4.0.
+C  V(RELDX) (IN) SCALED RELATIVE CHANGE IN X CAUSED BY STEP, COMPUTED
+C             (E.G.) BY FUNCTION  DRLDST  AS
+C                 MAX (D(I)*ABS(X(I)-X0(I)), 1 .LE. I .LE. P) /
+C                    MAX (D(I)*(ABS(X(I))+ABS(X0(I))), 1 .LE. I .LE. P).
+C V(RFCTOL) (IN)  RELATIVE FUNCTION CONVERGENCE TOLERANCE.  IF THE
+C             ACTUAL FUNCTION REDUCTION IS AT MOST TWICE WHAT WAS PRE-
+C             DICTED AND  V(NREDUC) .LE. V(RFCTOL)*ABS(V(F0)),  THEN
+C            DA7SST RETURNS WITH IV(IRC) = 8 OR 9.
+C  V(SCTOL) (IN)  SINGULAR CONVERGENCE TOLERANCE -- SEE V(LMAXS).
+C V(STPPAR) (IN)  MARQUARDT PARAMETER -- 0 MEANS FULL NEWTON STEP.
+C V(TUNER1) (IN)  TUNING CONSTANT USED TO DECIDE IF THE FUNCTION
+C             REDUCTION WAS MUCH LESS THAN EXPECTED.  SUGGESTED
+C             VALUE = 0.1.
+C V(TUNER2) (IN)  TUNING CONSTANT USED TO DECIDE IF THE FUNCTION
+C             REDUCTION WAS LARGE ENOUGH TO ACCEPT STEP.  SUGGESTED
+C             VALUE = 10**-4.
+C V(TUNER3) (IN)  TUNING CONSTANT USED TO DECIDE IF THE RADIUS
+C             SHOULD BE INCREASED.  SUGGESTED VALUE = 0.75.
+C  V(XCTOL) (IN)  X-CONVERGENCE CRITERION.  IF STEP IS A NEWTON STEP
+C             (V(STPPAR) = 0) HAVING V(RELDX) .LE. V(XCTOL) AND GIVING
+C             AT MOST TWICE THE PREDICTED FUNCTION DECREASE, THEN
+C            DA7SST RETURNS IV(IRC) = 7 OR 9.
+C  V(XFTOL) (IN)  FALSE CONVERGENCE TOLERANCE.  IF STEP GAVE NO OR ONLY
+C             A SMALL FUNCTION DECREASE AND V(RELDX) .LE. V(XFTOL),
+C             THEN DA7SST RETURNS WITH IV(IRC) = 12.
+C
+C-------------------------------  NOTES  -------------------------------
+C
+C  ***  APPLICATION AND USAGE RESTRICTIONS  ***
+C
+C        THIS ROUTINE IS CALLED AS PART OF THE NL2SOL (NONLINEAR
+C     LEAST-SQUARES) PACKAGE.  IT MAY BE USED IN ANY UNCONSTRAINED
+C     MINIMIZATION SOLVER THAT USES DOGLEG, GOLDFELD-QUANDT-TROTTER,
+C     OR LEVENBERG-MARQUARDT STEPS.
+C
+C  ***  ALGORITHM NOTES  ***
+C
+C        SEE (1) FOR FURTHER DISCUSSION OF THE ASSESSING AND MODEL
+C     SWITCHING STRATEGIES.  WHILE NL2SOL CONSIDERS ONLY TWO MODELS,
+C    DA7SST IS DESIGNED TO HANDLE ANY NUMBER OF MODELS.
+C
+C  ***  USAGE NOTES  ***
+C
+C        ON THE FIRST CALL OF AN ITERATION, ONLY THE I/O VARIABLES
+C     STEP, X, IV(IRC), IV(MODEL), V(F), V(DSTNRM), V(GTSTEP), AND
+C     V(PREDUC) NEED HAVE BEEN INITIALIZED.  BETWEEN CALLS, NO I/O
+C     VALUES EXCEPT STEP, X, IV(MODEL), V(F) AND THE STOPPING TOLER-
+C     ANCES SHOULD BE CHANGED.
+C        AFTER A RETURN FOR CONVERGENCE OR FALSE CONVERGENCE, ONE CAN
+C     CHANGE THE STOPPING TOLERANCES AND CALL DA7SST AGAIN, IN WHICH
+C     CASE THE STOPPING TESTS WILL BE REPEATED.
+C
+C  ***  REFERENCES  ***
+C
+C     (1) DENNIS, J.E., JR., GAY, D.M., AND WELSCH, R.E. (1981),
+C        AN ADAPTIVE NONLINEAR LEAST-SQUARES ALGORITHM,
+C        ACM TRANS. MATH. SOFTWARE, VOL. 7, NO. 3.
+C
+C     (2) POWELL, M.J.D. (1970)  A FORTRAN SUBROUTINE FOR SOLVING
+C        SYSTEMS OF NONLINEAR ALGEBRAIC EQUATIONS, IN NUMERICAL
+C        METHODS FOR NONLINEAR ALGEBRAIC EQUATIONS, EDITED BY
+C        P. RABINOWITZ, GORDON AND BREACH, LONDON.
+C
+C  ***  HISTORY  ***
+C
+C        JOHN DENNIS DESIGNED MUCH OF THIS ROUTINE, STARTING WITH
+C     IDEAS IN (2). ROY WELSCH SUGGESTED THE MODEL SWITCHING STRATEGY.
+C        DAVID GAY AND STEPHEN PETERS CAST THIS SUBROUTINE INTO A MORE
+C     PORTABLE FORM (WINTER 1977), AND DAVID GAY CAST IT INTO ITS
+C     PRESENT FORM (FALL 1978), WITH MINOR CHANGES TO THE SINGULAR
+C     CONVERGENCE TEST IN MAY, 1984 (TO DEAL WITH FULL NEWTON STEPS).
+C
+C  ***  GENERAL  ***
+C
+C     THIS SUBROUTINE WAS WRITTEN IN CONNECTION WITH RESEARCH
+C     SUPPORTED BY THE NATIONAL SCIENCE FOUNDATION UNDER GRANTS
+C     MCS-7600324, DCR75-10143, 76-14311DSS, MCS76-11989, AND
+C     MCS-7906671.
+C
+C------------------------  EXTERNAL QUANTITIES  ------------------------
+C
+C  ***  NO EXTERNAL FUNCTIONS AND SUBROUTINES  ***
+C
+C--------------------------  LOCAL VARIABLES  --------------------------
+C
+      LOGICAL GOODX
+      INTEGER I, NFC
+      DOUBLE PRECISION EMAX, EMAXS, GTS, RFAC1, XMAX
+      DOUBLE PRECISION HALF, ONE, ONEP2, TWO, ZERO
+C
+C  ***  SUBSCRIPTS FOR IV AND V  ***
+C
+      INTEGER AFCTOL, DECFAC, DSTNRM, DSTSAV, DST0, F, FDIF, FLSTGD, F0,
+     1        GTSLST, GTSTEP, INCFAC, IRC, LMAXS, MLSTGD, MODEL, NFCALL,
+     2        NFGCAL, NREDUC, PLSTGD, PREDUC, RADFAC, RADINC, RDFCMN,
+     3        RDFCMX, RELDX, RESTOR, RFCTOL, SCTOL, STAGE, STGLIM,
+     4        STPPAR, SWITCH, TOOBIG, TUNER1, TUNER2, TUNER3, XCTOL,
+     5        XFTOL, XIRC
+C
+C  ***  DATA INITIALIZATIONS  ***
+C
+      PARAMETER (HALF=0.5D+0, ONE=1.D+0, ONEP2=1.2D+0, TWO=2.D+0,
+     1           ZERO=0.D+0)
+C
+      PARAMETER (IRC=29, MLSTGD=32, MODEL=5, NFCALL=6, NFGCAL=7,
+     1           RADINC=8, RESTOR=9, STAGE=10, STGLIM=11, SWITCH=12,
+     2           TOOBIG=2, XIRC=13)
+      PARAMETER (AFCTOL=31, DECFAC=22, DSTNRM=2, DST0=3, DSTSAV=18,
+     1           F=10, FDIF=11, FLSTGD=12, F0=13, GTSLST=14, GTSTEP=4,
+     2           INCFAC=23, LMAXS=36, NREDUC=6, PLSTGD=15, PREDUC=7,
+     3           RADFAC=16, RDFCMN=24, RDFCMX=25, RELDX=17, RFCTOL=32,
+     4           SCTOL=37, STPPAR=5, TUNER1=26, TUNER2=27, TUNER3=28,
+     5           XCTOL=33, XFTOL=34)
+C
+C+++++++++++++++++++++++++++++++  BODY  ++++++++++++++++++++++++++++++++
+C
+      NFC = IV(NFCALL)
+      IV(SWITCH) = 0
+      IV(RESTOR) = 0
+      RFAC1 = ONE
+      GOODX = .TRUE.
+      I = IV(IRC)
+      IF (I .GE. 1 .AND. I .LE. 12)
+     1             GO TO (20,30,10,10,40,280,220,220,220,220,220,170), I
+         IV(IRC) = 13
+         GO TO 999
+C
+C  ***  INITIALIZE FOR NEW ITERATION  ***
+C
+ 10   IV(STAGE) = 1
+      IV(RADINC) = 0
+      V(FLSTGD) = V(F0)
+      IF (IV(TOOBIG) .EQ. 0) GO TO 110
+         IV(STAGE) = -1
+         IV(XIRC) = I
+         GO TO 60
+C
+C  ***  STEP WAS RECOMPUTED WITH NEW MODEL OR SMALLER RADIUS  ***
+C  ***  FIRST DECIDE WHICH  ***
+C
+ 20   IF (IV(MODEL) .NE. IV(MLSTGD)) GO TO 30
+C        ***  OLD MODEL RETAINED, SMALLER RADIUS TRIED  ***
+C        ***  DO NOT CONSIDER ANY MORE NEW MODELS THIS ITERATION  ***
+         IV(STAGE) = IV(STGLIM)
+         IV(RADINC) = -1
+         GO TO 110
+C
+C  ***  A NEW MODEL IS BEING TRIED.  DECIDE WHETHER TO KEEP IT.  ***
+C
+ 30   IV(STAGE) = IV(STAGE) + 1
+C
+C     ***  NOW WE ADD THE POSSIBILITY THAT STEP WAS RECOMPUTED WITH  ***
+C     ***  THE SAME MODEL, PERHAPS BECAUSE OF AN OVERSIZED STEP.     ***
+C
+ 40   IF (IV(STAGE) .GT. 0) GO TO 50
+C
+C        ***  STEP WAS RECOMPUTED BECAUSE IT WAS TOO BIG.  ***
+C
+         IF (IV(TOOBIG) .NE. 0) GO TO 60
+C
+C        ***  RESTORE IV(STAGE) AND PICK UP WHERE WE LEFT OFF.  ***
+C
+         IV(STAGE) = -IV(STAGE)
+         I = IV(XIRC)
+         GO TO (20, 30, 110, 110, 70), I
+C
+ 50   IF (IV(TOOBIG) .EQ. 0) GO TO 70
+C
+C  ***  HANDLE OVERSIZE STEP  ***
+C
+      IV(TOOBIG) = 0
+      IF (IV(RADINC) .GT. 0) GO TO 80
+         IV(STAGE) = -IV(STAGE)
+         IV(XIRC) = IV(IRC)
+C
+ 60      IV(TOOBIG) = 0
+         V(RADFAC) = V(DECFAC)
+         IV(RADINC) = IV(RADINC) - 1
+         IV(IRC) = 5
+         IV(RESTOR) = 1
+         V(F) = V(FLSTGD)
+         GO TO 999
+C
+ 70   IF (V(F) .LT. V(FLSTGD)) GO TO 110
+C
+C     *** THE NEW STEP IS A LOSER.  RESTORE OLD MODEL.  ***
+C
+      IF (IV(MODEL) .EQ. IV(MLSTGD)) GO TO 80
+         IV(MODEL) = IV(MLSTGD)
+         IV(SWITCH) = 1
+C
+C     ***  RESTORE STEP, ETC. ONLY IF A PREVIOUS STEP DECREASED V(F).
+C
+ 80   IF (V(FLSTGD) .GE. V(F0)) GO TO 110
+         IF (IV(STAGE) .LT. IV(STGLIM)) THEN
+            GOODX = .FALSE.
+         ELSE IF (NFC .LT. IV(NFGCAL) + IV(STGLIM) + 2) THEN
+            GOODX = .FALSE.
+         ELSE IF (IV(SWITCH) .NE. 0) THEN
+            GOODX = .FALSE.
+            ENDIF
+         IV(RESTOR) = 3
+         V(F) = V(FLSTGD)
+         V(PREDUC) = V(PLSTGD)
+         V(GTSTEP) = V(GTSLST)
+         IF (IV(SWITCH) .EQ. 0) RFAC1 = V(DSTNRM) / V(DSTSAV)
+         V(DSTNRM) = V(DSTSAV)
+         IF (GOODX) THEN
+C
+C     ***  ACCEPT PREVIOUS SLIGHTLY REDUCING STEP ***
+C
+            V(FDIF) = V(F0) - V(F)
+            IV(IRC) = 4
+            V(RADFAC) = RFAC1
+            GO TO 999
+            ENDIF
+         NFC = IV(NFGCAL)
+C
+ 110  V(FDIF) = V(F0) - V(F)
+      IF (V(FDIF) .GT. V(TUNER2) * V(PREDUC)) GO TO 140
+      IF (IV(RADINC) .GT. 0) GO TO 140
+C
+C        ***  NO (OR ONLY A TRIVIAL) FUNCTION DECREASE
+C        ***  -- SO TRY NEW MODEL OR SMALLER RADIUS
+C
+         IF (V(F) .LT. V(F0)) GO TO 120
+              IV(MLSTGD) = IV(MODEL)
+              V(FLSTGD) = V(F)
+              V(F) = V(F0)
+              IV(RESTOR) = 1
+              GO TO 130
+ 120     IV(NFGCAL) = NFC
+ 130     IV(IRC) = 1
+         IF (IV(STAGE) .LT. IV(STGLIM)) GO TO 160
+              IV(IRC) = 5
+              IV(RADINC) = IV(RADINC) - 1
+              GO TO 160
+C
+C  ***  NONTRIVIAL FUNCTION DECREASE ACHIEVED  ***
+C
+ 140  IV(NFGCAL) = NFC
+      RFAC1 = ONE
+      V(DSTSAV) = V(DSTNRM)
+      IF (V(FDIF) .GT. V(PREDUC)*V(TUNER1)) GO TO 190
+C
+C  ***  DECREASE WAS MUCH LESS THAN PREDICTED -- EITHER CHANGE MODELS
+C  ***  OR ACCEPT STEP WITH DECREASED RADIUS.
+C
+      IF (IV(STAGE) .GE. IV(STGLIM)) GO TO 150
+C        ***  CONSIDER SWITCHING MODELS  ***
+         IV(IRC) = 2
+         GO TO 160
+C
+C     ***  ACCEPT STEP WITH DECREASED RADIUS  ***
+C
+ 150  IV(IRC) = 4
+C
+C  ***  SET V(RADFAC) TO FLETCHER*S DECREASE FACTOR  ***
+C
+ 160  IV(XIRC) = IV(IRC)
+      EMAX = V(GTSTEP) + V(FDIF)
+      V(RADFAC) = HALF * RFAC1
+      IF (EMAX .LT. V(GTSTEP)) V(RADFAC) = RFAC1 * DMAX1(V(RDFCMN),
+     1                                           HALF * V(GTSTEP)/EMAX)
+C
+C  ***  DO FALSE CONVERGENCE TEST  ***
+C
+ 170  IF (V(RELDX) .LE. V(XFTOL)) GO TO 180
+         IV(IRC) = IV(XIRC)
+         IF (V(F) .LT. V(F0)) GO TO 200
+              GO TO 230
+C
+ 180  IV(IRC) = 12
+      GO TO 240
+C
+C  ***  HANDLE GOOD FUNCTION DECREASE  ***
+C
+ 190  IF (V(FDIF) .LT. (-V(TUNER3) * V(GTSTEP))) GO TO 210
+C
+C     ***  INCREASING RADIUS LOOKS WORTHWHILE.  SEE IF WE JUST
+C     ***  RECOMPUTED STEP WITH A DECREASED RADIUS OR RESTORED STEP
+C     ***  AFTER RECOMPUTING IT WITH A LARGER RADIUS.
+C
+      IF (IV(RADINC) .LT. 0) GO TO 210
+      IF (IV(RESTOR) .EQ. 1) GO TO 210
+      IF (IV(RESTOR) .EQ. 3) GO TO 210
+C
+C        ***  WE DID NOT.  TRY A LONGER STEP UNLESS THIS WAS A NEWTON
+C        ***  STEP.
+C
+         V(RADFAC) = V(RDFCMX)
+         GTS = V(GTSTEP)
+         IF (V(FDIF) .LT. (HALF/V(RADFAC) - ONE) * GTS)
+     1            V(RADFAC) = DMAX1(V(INCFAC), HALF*GTS/(GTS + V(FDIF)))
+         IV(IRC) = 4
+         IF (V(STPPAR) .EQ. ZERO) GO TO 230
+         IF (V(DST0) .GE. ZERO .AND. (V(DST0) .LT. TWO*V(DSTNRM)
+     1             .OR. V(NREDUC) .LT. ONEP2*V(FDIF)))  GO TO 230
+C             ***  STEP WAS NOT A NEWTON STEP.  RECOMPUTE IT WITH
+C             ***  A LARGER RADIUS.
+              IV(IRC) = 5
+              IV(RADINC) = IV(RADINC) + 1
+C
+C  ***  SAVE VALUES CORRESPONDING TO GOOD STEP  ***
+C
+ 200  V(FLSTGD) = V(F)
+      IV(MLSTGD) = IV(MODEL)
+      IF (IV(RESTOR) .EQ. 0) IV(RESTOR) = 2
+      V(DSTSAV) = V(DSTNRM)
+      IV(NFGCAL) = NFC
+      V(PLSTGD) = V(PREDUC)
+      V(GTSLST) = V(GTSTEP)
+      GO TO 230
+C
+C  ***  ACCEPT STEP WITH RADIUS UNCHANGED  ***
+C
+ 210  V(RADFAC) = ONE
+      IV(IRC) = 3
+      GO TO 230
+C
+C  ***  COME HERE FOR A RESTART AFTER CONVERGENCE  ***
+C
+ 220  IV(IRC) = IV(XIRC)
+      IF (V(DSTSAV) .GE. ZERO) GO TO 240
+         IV(IRC) = 12
+         GO TO 240
+C
+C  ***  PERFORM CONVERGENCE TESTS  ***
+C
+ 230  IV(XIRC) = IV(IRC)
+ 240  IF (IV(RESTOR) .EQ. 1 .AND. V(FLSTGD) .LT. V(F0)) IV(RESTOR) = 3
+      IF (DABS(V(F)) .LT. V(AFCTOL)) IV(IRC) = 10
+      IF (HALF * V(FDIF) .GT. V(PREDUC)) GO TO 999
+      EMAX = V(RFCTOL) * DABS(V(F0))
+      EMAXS = V(SCTOL) * DABS(V(F0))
+      IF (V(PREDUC) .LE. EMAXS .AND. (V(DSTNRM) .GT. V(LMAXS) .OR.
+     1     V(STPPAR) .EQ. ZERO)) IV(IRC) = 11
+      IF (V(DST0) .LT. ZERO) GO TO 250
+      I = 0
+      IF ((V(NREDUC) .GT. ZERO .AND. V(NREDUC) .LE. EMAX) .OR.
+     1    (V(NREDUC) .EQ. ZERO. AND. V(PREDUC) .EQ. ZERO))  I = 2
+      IF (V(STPPAR) .EQ. ZERO .AND. V(RELDX) .LE. V(XCTOL)
+     1                        .AND. GOODX)                  I = I + 1
+      IF (I .GT. 0) IV(IRC) = I + 6
+C
+C  ***  CONSIDER RECOMPUTING STEP OF LENGTH V(LMAXS) FOR SINGULAR
+C  ***  CONVERGENCE TEST.
+C
+ 250  IF (IV(IRC) .GT. 5 .AND. IV(IRC) .NE. 12) GO TO 999
+      IF (V(STPPAR) .EQ. ZERO) GO TO 999
+      IF (V(DSTNRM) .GT. V(LMAXS)) GO TO 260
+         IF (V(PREDUC) .GE. EMAXS) GO TO 999
+              IF (V(DST0) .LE. ZERO) GO TO 270
+                   IF (HALF * V(DST0) .LE. V(LMAXS)) GO TO 999
+                        GO TO 270
+ 260  IF (HALF * V(DSTNRM) .LE. V(LMAXS)) GO TO 999
+      XMAX = V(LMAXS) / V(DSTNRM)
+      IF (XMAX * (TWO - XMAX) * V(PREDUC) .GE. EMAXS) GO TO 999
+ 270  IF (V(NREDUC) .LT. ZERO) GO TO 290
+C
+C  ***  RECOMPUTE V(PREDUC) FOR USE IN SINGULAR CONVERGENCE TEST  ***
+C
+      V(GTSLST) = V(GTSTEP)
+      V(DSTSAV) = V(DSTNRM)
+      IF (IV(IRC) .EQ. 12) V(DSTSAV) = -V(DSTSAV)
+      V(PLSTGD) = V(PREDUC)
+      I = IV(RESTOR)
+      IV(RESTOR) = 2
+      IF (I .EQ. 3) IV(RESTOR) = 0
+      IV(IRC) = 6
+      GO TO 999
+C
+C  ***  PERFORM SINGULAR CONVERGENCE TEST WITH RECOMPUTED V(PREDUC)  ***
+C
+ 280  V(GTSTEP) = V(GTSLST)
+      V(DSTNRM) = DABS(V(DSTSAV))
+      IV(IRC) = IV(XIRC)
+      IF (V(DSTSAV) .LE. ZERO) IV(IRC) = 12
+      V(NREDUC) = -V(PREDUC)
+      V(PREDUC) = V(PLSTGD)
+      IV(RESTOR) = 3
+ 290  IF (-V(NREDUC) .LE. V(SCTOL) * DABS(V(F0))) IV(IRC) = 11
+C
+ 999  RETURN
+C
+C  ***  LAST LINE OF DA7SST FOLLOWS  ***
+      END
+      SUBROUTINE I7SHFT(N, K, X)
+C
+C  ***  SHIFT X(K),...,X(N) LEFT CIRCULARLY ONE POSITION IF K .GT. 0.
+C  ***  SHIFT X(-K),...,X(N) RIGHT CIRCULARLY ONE POSITION IF K .LT. 0.
+C
+      INTEGER N, K
+      INTEGER X(N)
+C
+      INTEGER I, II, K1, NM1, T
+C
+      IF (K .LT. 0) GO TO 20
+      IF (K .GE. N) GO TO 999
+      NM1 = N - 1
+      T = X(K)
+      DO 10 I = K, NM1
+ 10      X(I) = X(I+1)
+      X(N) = T
+      GO TO 999
+C
+ 20   K1 = -K
+      IF (K1 .GE. N) GO TO 999
+      T = X(N)
+      NM1 = N - K1
+      DO 30 II = 1, NM1
+         I = N - II
+         X(I+1) = X(I)
+ 30      CONTINUE
+      X(K1) = T
+ 999  RETURN
+C  ***  LAST LINE OF I7SHFT FOLLOWS  ***
+      END
+      SUBROUTINE S7ETR(M,N,INDROW,JPNTR,INDCOL,IPNTR,IWA)
+      INTEGER M,N
+      INTEGER INDROW(1),JPNTR(1),INDCOL(1),IPNTR(1),IWA(M)
+C     **********
+C
+C     SUBROUTINE S7ETR
+C
+C     GIVEN A COLUMN-ORIENTED DEFINITION OF THE SPARSITY PATTERN
+C     OF AN M BY N MATRIX A, THIS SUBROUTINE DETERMINES A
+C     ROW-ORIENTED DEFINITION OF THE SPARSITY PATTERN OF A.
+C
+C     ON INPUT THE COLUMN-ORIENTED DEFINITION IS SPECIFIED BY
+C     THE ARRAYS INDROW AND JPNTR. ON OUTPUT THE ROW-ORIENTED
+C     DEFINITION IS SPECIFIED BY THE ARRAYS INDCOL AND IPNTR.
+C
+C     THE SUBROUTINE STATEMENT IS
+C
+C       SUBROUTINE S7ETR(M,N,INDROW,JPNTR,INDCOL,IPNTR,IWA)
+C
+C     WHERE
+C
+C       M IS A POSITIVE INTEGER INPUT VARIABLE SET TO THE NUMBER
+C         OF ROWS OF A.
+C
+C       N IS A POSITIVE INTEGER INPUT VARIABLE SET TO THE NUMBER
+C         OF COLUMNS OF A.
+C
+C       INDROW IS AN INTEGER INPUT ARRAY WHICH CONTAINS THE ROW
+C         INDICES FOR THE NON-ZEROES IN THE MATRIX A.
+C
+C       JPNTR IS AN INTEGER INPUT ARRAY OF LENGTH N + 1 WHICH
+C         SPECIFIES THE LOCATIONS OF THE ROW INDICES IN INDROW.
+C         THE ROW INDICES FOR COLUMN J ARE
+C
+C               INDROW(K), K = JPNTR(J),...,JPNTR(J+1)-1.
+C
+C         NOTE THAT JPNTR(N+1)-1 IS THEN THE NUMBER OF NON-ZERO
+C         ELEMENTS OF THE MATRIX A.
+C
+C       INDCOL IS AN INTEGER OUTPUT ARRAY WHICH CONTAINS THE
+C         COLUMN INDICES FOR THE NON-ZEROES IN THE MATRIX A.
+C
+C       IPNTR IS AN INTEGER OUTPUT ARRAY OF LENGTH M + 1 WHICH
+C         SPECIFIES THE LOCATIONS OF THE COLUMN INDICES IN INDCOL.
+C         THE COLUMN INDICES FOR ROW I ARE
+C
+C               INDCOL(K), K = IPNTR(I),...,IPNTR(I+1)-1.
+C
+C         NOTE THAT IPNTR(1) IS SET TO 1 AND THAT IPNTR(M+1)-1 IS
+C         THEN THE NUMBER OF NON-ZERO ELEMENTS OF THE MATRIX A.
+C
+C       IWA IS AN INTEGER WORK ARRAY OF LENGTH M.
+C
+C     ARGONNE NATIONAL LABORATORY. MINPACK PROJECT. JUNE 1982.
+C     THOMAS F. COLEMAN, BURTON S. GARBOW, JORGE J. MORE
+C
+C     **********
+      INTEGER IR,JCOL,JP,JPL,JPU,L,NNZ
+C
+C     DETERMINE THE NUMBER OF NON-ZEROES IN THE ROWS.
+C
+      DO 10 IR = 1, M
+         IWA(IR) = 0
+   10    CONTINUE
+      NNZ = JPNTR(N+1) - 1
+      DO 20 JP = 1, NNZ
+         IR = INDROW(JP)
+         IWA(IR) = IWA(IR) + 1
+   20    CONTINUE
+C
+C     SET POINTERS TO THE START OF THE ROWS IN INDCOL.
+C
+      IPNTR(1) = 1
+      DO 30 IR = 1, M
+         IPNTR(IR+1) = IPNTR(IR) + IWA(IR)
+         IWA(IR) = IPNTR(IR)
+   30    CONTINUE
+C
+C     FILL INDCOL.
+C
+      DO 60 JCOL = 1, N
+         JPL = JPNTR(JCOL)
+         JPU = JPNTR(JCOL+1) - 1
+         IF (JPU .LT. JPL) GO TO 50
+         DO 40 JP = JPL, JPU
+            IR = INDROW(JP)
+            L = IWA(IR)
+            INDCOL(L) = JCOL
+            IWA(IR) = IWA(IR) + 1
+   40       CONTINUE
+   50    CONTINUE
+   60    CONTINUE
+      RETURN
+C
+C     LAST CARD OF SUBROUTINE S7ETR.
+C
+      END
+      SUBROUTINE DG7QSB(B, D, DIHDI, G, IPIV, IPIV1, IPIV2, KA, L, LV,
+     1                  P, P0, PC, STEP, TD, TG, V, W, X, X0)
+C
+C  ***  COMPUTE HEURISTIC BOUNDED NEWTON STEP  ***
+C
+      INTEGER KA, LV, P, P0, PC
+      INTEGER IPIV(P), IPIV1(P), IPIV2(P)
+      DOUBLE PRECISION B(2,P), D(P), DIHDI(*), G(P), L(*),
+     1                 STEP(P,2), TD(P), TG(P), V(LV), W(P), X0(P), X(P)
+C     DIMENSION DIHDI(P*(P+1)/2), L(P*(P+1)/2)
+C
+      DOUBLE PRECISION DD7TPR
+      EXTERNAL DD7TPR,DG7QTS, DS7BQN, DS7IPR,DV7CPY, DV7IPR,
+     1         DV7SCP, DV7VMP
+C
+C  ***  LOCAL VARIABLES  ***
+C
+      INTEGER K, KB, KINIT, NS, P1, P10
+      DOUBLE PRECISION DS0, NRED, PRED, RAD
+      DOUBLE PRECISION ZERO
+C
+C  ***  V SUBSCRIPTS  ***
+C
+      INTEGER DST0, DSTNRM, GTSTEP, NREDUC, PREDUC, RADIUS
+C
+      PARAMETER (DST0=3, DSTNRM=2, GTSTEP=4, NREDUC=6, PREDUC=7,
+     1           RADIUS=8)
+      DATA ZERO/0.D+0/
+C
+C+++++++++++++++++++++++++++++++  BODY  ++++++++++++++++++++++++++++++++
+C
+      P1 = PC
+      IF (KA .LT. 0) GO TO 10
+         NRED = V(NREDUC)
+         DS0 = V(DST0)
+         GO TO 20
+ 10   P0 = 0
+      KA = -1
+C
+ 20   KINIT = -1
+      IF (P0 .EQ. P1) KINIT = KA
+      CALL DV7CPY(P, X, X0)
+      PRED = ZERO
+      RAD = V(RADIUS)
+      KB = -1
+      V(DSTNRM) = ZERO
+      IF (P1 .GT. 0) GO TO 30
+         NRED = ZERO
+         DS0 = ZERO
+         CALL DV7SCP(P, STEP, ZERO)
+         GO TO 60
+C
+ 30   CALL DV7CPY(P, TD, D)
+      CALL DV7IPR(P, IPIV, TD)
+      CALL DV7VMP(P, TG, G, D, -1)
+      CALL DV7IPR(P, IPIV, TG)
+ 40   K = KINIT
+      KINIT = -1
+      V(RADIUS) = RAD - V(DSTNRM)
+      CALL DG7QTS(TD, TG, DIHDI, K, L, P1, STEP, V, W)
+      P0 = P1
+      IF (KA .GE. 0) GO TO 50
+         NRED = V(NREDUC)
+         DS0 = V(DST0)
+C
+ 50   KA = K
+      V(RADIUS) = RAD
+      P10 = P1
+      CALL DS7BQN(B, D, STEP(1,2), IPIV, IPIV1, IPIV2, KB, L, LV,
+     1            NS, P, P1, STEP, TD, TG, V, W, X, X0)
+      IF (NS .GT. 0) CALL DS7IPR(P10, IPIV1, DIHDI)
+      PRED = PRED + V(PREDUC)
+      IF (NS .NE. 0) P0 = 0
+      IF (KB .LE. 0) GO TO 40
+C
+ 60   V(DST0) = DS0
+      V(NREDUC) = NRED
+      V(PREDUC) = PRED
+      V(GTSTEP) = DD7TPR(P, G, STEP)
+C
+      RETURN
+C  ***  LAST LINE OF DG7QSB FOLLOWS  ***
+      END
+      DOUBLE PRECISION FUNCTION DL7SVX(P, L, X, Y)
+C
+C  ***  ESTIMATE LARGEST SING. VALUE OF PACKED LOWER TRIANG. MATRIX L
+C
+C  ***  PARAMETER DECLARATIONS  ***
+C
+      INTEGER P
+      DOUBLE PRECISION L(*), X(P), Y(P)
+C     DIMENSION L(P*(P+1)/2)
+C
+C+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+C
+C  ***  PURPOSE  ***
+C
+C     THIS FUNCTION RETURNS A GOOD UNDER-ESTIMATE OF THE LARGEST
+C     SINGULAR VALUE OF THE PACKED LOWER TRIANGULAR MATRIX L.
+C
+C  ***  PARAMETER DESCRIPTION  ***
+C
+C  P (IN)  = THE ORDER OF L.  L IS A  P X P  LOWER TRIANGULAR MATRIX.
+C  L (IN)  = ARRAY HOLDING THE ELEMENTS OF  L  IN ROW ORDER, I.E.
+C             L(1,1), L(2,1), L(2,2), L(3,1), L(3,2), L(3,3), ETC.
+C  X (OUT) IF DL7SVX RETURNS A POSITIVE VALUE, THEN X = (L**T)*Y IS AN
+C             (UNNORMALIZED) APPROXIMATE RIGHT SINGULAR VECTOR
+C             CORRESPONDING TO THE LARGEST SINGULAR VALUE.  THIS
+C             APPROXIMATION MAY BE CRUDE.
+C  Y (OUT) IF DL7SVX RETURNS A POSITIVE VALUE, THEN Y = L*X IS A
+C             NORMALIZED APPROXIMATE LEFT SINGULAR VECTOR CORRESPOND-
+C             ING TO THE LARGEST SINGULAR VALUE.  THIS APPROXIMATION
+C             MAY BE VERY CRUDE.  THE CALLER MAY PASS THE SAME VECTOR
+C             FOR X AND Y (NONSTANDARD FORTRAN USAGE), IN WHICH CASE X
+C             OVER-WRITES Y.
+C
+C  ***  ALGORITHM NOTES  ***
+C
+C     THE ALGORITHM IS BASED ON ANALOGY WITH (1).  IT USES A
+C     RANDOM NUMBER GENERATOR PROPOSED IN (4), WHICH PASSES THE
+C     SPECTRAL TEST WITH FLYING COLORS -- SEE (2) AND (3).
+C
+C  ***  SUBROUTINES AND FUNCTIONS CALLED  ***
+C
+C        DV2NRM - FUNCTION, RETURNS THE 2-NORM OF A VECTOR.
+C
+C  ***  REFERENCES  ***
+C
+C     (1) CLINE, A., MOLER, C., STEWART, G., AND WILKINSON, J.H.(1977),
+C         AN ESTIMATE FOR THE CONDITION NUMBER OF A MATRIX, REPORT
+C         TM-310, APPLIED MATH. DIV., ARGONNE NATIONAL LABORATORY.
+C
+C     (2) HOAGLIN, D.C. (1976), THEORETICAL PROPERTIES OF CONGRUENTIAL
+C         RANDOM-NUMBER GENERATORS --  AN EMPIRICAL VIEW,
+C         MEMORANDUM NS-340, DEPT. OF STATISTICS, HARVARD UNIV.
+C
+C     (3) KNUTH, D.E. (1969), THE ART OF COMPUTER PROGRAMMING, VOL. 2
+C         (SEMINUMERICAL ALGORITHMS), ADDISON-WESLEY, READING, MASS.
+C
+C     (4) SMITH, C.S. (1971), MULTIPLICATIVE PSEUDO-RANDOM NUMBER
+C         GENERATORS WITH PRIME MODULUS, J. ASSOC. COMPUT. MACH. 18,
+C         PP. 586-593.
+C
+C  ***  HISTORY  ***
+C
+C     DESIGNED AND CODED BY DAVID M. GAY (WINTER 1977/SUMMER 1978).
+C
+C  ***  GENERAL  ***
+C
+C     THIS SUBROUTINE WAS WRITTEN IN CONNECTION WITH RESEARCH
+C     SUPPORTED BY THE NATIONAL SCIENCE FOUNDATION UNDER GRANTS
+C     MCS-7600324, DCR75-10143, 76-14311DSS, AND MCS76-11989.
+C
+C+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+C
+C  ***  LOCAL VARIABLES  ***
+C
+      INTEGER I, IX, J, JI, JJ, JJJ, JM1, J0, PM1, PPLUS1
+      DOUBLE PRECISION B, BLJI, SMINUS, SPLUS, T, YI
+C
+C  ***  CONSTANTS  ***
+C
+      DOUBLE PRECISION HALF, ONE, R9973, ZERO
+C
+C  ***  EXTERNAL FUNCTIONS AND SUBROUTINES  ***
+C
+      DOUBLE PRECISION DD7TPR, DV2NRM
+      EXTERNAL DD7TPR, DV2NRM,DV2AXY
+C
+      PARAMETER (HALF=0.5D+0, ONE=1.D+0, R9973=9973.D+0, ZERO=0.D+0)
+C
+C  ***  BODY  ***
+C
+      IX = 2
+      PPLUS1 = P + 1
+      PM1 = P - 1
+C
+C  ***  FIRST INITIALIZE X TO PARTIAL SUMS  ***
+C
+      J0 = P*PM1/2
+      JJ = J0 + P
+      IX = MOD(3432*IX, 9973)
+      B = HALF*(ONE + DBLE(IX)/R9973)
+      X(P) = B * L(JJ)
+      IF (P .LE. 1) GO TO 40
+      DO 10 I = 1, PM1
+         JI = J0 + I
+         X(I) = B * L(JI)
+ 10      CONTINUE
+C
+C  ***  COMPUTE X = (L**T)*B, WHERE THE COMPONENTS OF B HAVE RANDOMLY
+C  ***  CHOSEN MAGNITUDES IN (.5,1) WITH SIGNS CHOSEN TO MAKE X LARGE.
+C
+C     DO J = P-1 TO 1 BY -1...
+      DO 30 JJJ = 1, PM1
+         J = P - JJJ
+C       ***  DETERMINE X(J) IN THIS ITERATION. NOTE FOR I = 1,2,...,J
+C       ***  THAT X(I) HOLDS THE CURRENT PARTIAL SUM FOR ROW I.
+         IX = MOD(3432*IX, 9973)
+         B = HALF*(ONE + DBLE(IX)/R9973)
+         JM1 = J - 1
+         J0 = J*JM1/2
+         SPLUS = ZERO
+         SMINUS = ZERO
+         DO 20 I = 1, J
+              JI = J0 + I
+              BLJI = B * L(JI)
+              SPLUS = SPLUS + DABS(BLJI + X(I))
+              SMINUS = SMINUS + DABS(BLJI - X(I))
+ 20           CONTINUE
+         IF (SMINUS .GT. SPLUS) B = -B
+         X(J) = ZERO
+C        ***  UPDATE PARTIAL SUMS  ***
+         CALL DV2AXY(J, X, B, L(J0+1), X)
+ 30      CONTINUE
+C
+C  ***  NORMALIZE X  ***
+C
+ 40   T = DV2NRM(P, X)
+      IF (T .LE. ZERO) GO TO 80
+      T = ONE / T
+      DO 50 I = 1, P
+ 50      X(I) = T*X(I)
+C
+C  ***  COMPUTE L*X = Y AND RETURN SVMAX = TWONORM(Y)  ***
+C
+      DO 60 JJJ = 1, P
+         J = PPLUS1 - JJJ
+         JI = J*(J-1)/2 + 1
+         Y(J) = DD7TPR(J, L(JI), X)
+ 60      CONTINUE
+C
+C  ***  NORMALIZE Y AND SET X = (L**T)*Y  ***
+C
+      T = ONE / DV2NRM(P, Y)
+      JI = 1
+      DO 70 I = 1, P
+         YI = T * Y(I)
+         X(I) = ZERO
+         CALL DV2AXY(I, X, YI, L(JI), X)
+         JI = JI + I
+ 70      CONTINUE
+      DL7SVX = DV2NRM(P, X)
+      GO TO 999
+C
+ 80   DL7SVX = ZERO
+C
+ 999  RETURN
+C  ***  LAST CARD OF DL7SVX FOLLOWS  ***
+      END
+      SUBROUTINE DD7DUP(D, HDIAG, IV, LIV, LV, N, V)
+C
+C  ***  UPDATE SCALE VECTOR D FOR  DMNH  ***
+C
+C  ***  PARAMETER DECLARATIONS  ***
+C
+      INTEGER LIV, LV, N
+      INTEGER IV(LIV)
+      DOUBLE PRECISION D(N), HDIAG(N), V(LV)
+C
+C  ***  LOCAL VARIABLES  ***
+C
+      INTEGER DTOLI, D0I, I
+      DOUBLE PRECISION T, VDFAC
+C
+C  ***  INTRINSIC FUNCTIONS  ***
+C/+
+      DOUBLE PRECISION DSQRT
+C/
+C  ***  SUBSCRIPTS FOR IV AND V  ***
+C
+      INTEGER DFAC, DTOL, DTYPE, NITER
+      PARAMETER (DFAC=41, DTOL=59, DTYPE=16, NITER=31)
+C
+C-------------------------------  BODY  --------------------------------
+C
+      I = IV(DTYPE)
+      IF (I .EQ. 1) GO TO 10
+         IF (IV(NITER) .GT. 0) GO TO 999
+C
+ 10   DTOLI = IV(DTOL)
+      D0I = DTOLI + N
+      VDFAC = V(DFAC)
+      DO 20 I = 1, N
+         T = DMAX1(DSQRT(DABS(HDIAG(I))), VDFAC*D(I))
+         IF (T .LT. V(DTOLI)) T = DMAX1(V(DTOLI), V(D0I))
+         D(I) = T
+         DTOLI = DTOLI + 1
+         D0I = D0I + 1
+ 20      CONTINUE
+C
+ 999  RETURN
+C  ***  LAST CARD OF DD7DUP FOLLOWS  ***
+      END
+      SUBROUTINE S7RTDT(N,NNZ,INDROW,INDCOL,JPNTR,IWA)
+      INTEGER N,NNZ
+      INTEGER INDROW(NNZ),INDCOL(NNZ),JPNTR(1),IWA(N)
+C     **********
+C
+C     SUBROUTINE S7RTDT
+C
+C     GIVEN THE NON-ZERO ELEMENTS OF AN M BY N MATRIX A IN
+C     ARBITRARY ORDER AS SPECIFIED BY THEIR ROW AND COLUMN
+C     INDICES, THIS SUBROUTINE PERMUTES THESE ELEMENTS SO
+C     THAT THEIR COLUMN INDICES ARE IN NON-DECREASING ORDER.
+C
+C     ON INPUT IT IS ASSUMED THAT THE ELEMENTS ARE SPECIFIED IN
+C
+C           INDROW(K),INDCOL(K), K = 1,...,NNZ.
+C
+C     ON OUTPUT THE ELEMENTS ARE PERMUTED SO THAT INDCOL IS
+C     IN NON-DECREASING ORDER. IN ADDITION, THE ARRAY JPNTR
+C     IS SET SO THAT THE ROW INDICES FOR COLUMN J ARE
+C
+C           INDROW(K), K = JPNTR(J),...,JPNTR(J+1)-1.
+C
+C     NOTE THAT THE VALUE OF M IS NOT NEEDED BY S7RTDT AND IS
+C     THEREFORE NOT PRESENT IN THE SUBROUTINE STATEMENT.
+C
+C     THE SUBROUTINE STATEMENT IS
+C
+C       SUBROUTINE S7RTDT(N,NNZ,INDROW,INDCOL,JPNTR,IWA)
+C
+C     WHERE
+C
+C       N IS A POSITIVE INTEGER INPUT VARIABLE SET TO THE NUMBER
+C         OF COLUMNS OF A.
+C
+C       NNZ IS A POSITIVE INTEGER INPUT VARIABLE SET TO THE NUMBER
+C         OF NON-ZERO ELEMENTS OF A.
+C
+C       INDROW IS AN INTEGER ARRAY OF LENGTH NNZ. ON INPUT INDROW
+C         MUST CONTAIN THE ROW INDICES OF THE NON-ZERO ELEMENTS OF A.
+C         ON OUTPUT INDROW IS PERMUTED SO THAT THE CORRESPONDING
+C         COLUMN INDICES OF INDCOL ARE IN NON-DECREASING ORDER.
+C
+C       INDCOL IS AN INTEGER ARRAY OF LENGTH NNZ. ON INPUT INDCOL
+C         MUST CONTAIN THE COLUMN INDICES OF THE NON-ZERO ELEMENTS
+C         OF A. ON OUTPUT INDCOL IS PERMUTED SO THAT THESE INDICES
+C         ARE IN NON-DECREASING ORDER.
+C
+C       JPNTR IS AN INTEGER OUTPUT ARRAY OF LENGTH N + 1 WHICH
+C         SPECIFIES THE LOCATIONS OF THE ROW INDICES IN THE OUTPUT
+C         INDROW. THE ROW INDICES FOR COLUMN J ARE
+C
+C               INDROW(K), K = JPNTR(J),...,JPNTR(J+1)-1.
+C
+C         NOTE THAT JPNTR(1) IS SET TO 1 AND THAT JPNTR(N+1)-1
+C         IS THEN NNZ.
+C
+C       IWA IS AN INTEGER WORK ARRAY OF LENGTH N.
+C
+C     SUBPROGRAMS CALLED
+C
+C       FORTRAN-SUPPLIED ... MAX0
+C
+C     ARGONNE NATIONAL LABORATORY. MINPACK PROJECT. JUNE 1982.
+C     THOMAS F. COLEMAN, BURTON S. GARBOW, JORGE J. MORE
+C
+C     **********
+      INTEGER I,J,K,L
+C
+C     DETERMINE THE NUMBER OF NON-ZEROES IN THE COLUMNS.
+C
+      DO 10 J = 1, N
+         IWA(J) = 0
+   10    CONTINUE
+      DO 20 K = 1, NNZ
+         J = INDCOL(K)
+         IWA(J) = IWA(J) + 1
+   20    CONTINUE
+C
+C     SET POINTERS TO THE START OF THE COLUMNS IN INDROW.
+C
+      JPNTR(1) = 1
+      DO 30 J = 1, N
+         JPNTR(J+1) = JPNTR(J) + IWA(J)
+         IWA(J) = JPNTR(J)
+   30    CONTINUE
+      K = 1
+C
+C     BEGIN IN-PLACE SORT.
+C
+   40 CONTINUE
+         J = INDCOL(K)
+         IF (K .LT. JPNTR(J) .OR. K .GE. JPNTR(J+1)) GO TO 50
+C
+C           CURRENT ELEMENT IS IN POSITION. NOW EXAMINE THE
+C           NEXT ELEMENT OR THE FIRST UN-SORTED ELEMENT IN
+C           THE J-TH GROUP.
+C
+            K = MAX0(K+1,IWA(J))
+            GO TO 60
+   50    CONTINUE
+C
+C           CURRENT ELEMENT IS NOT IN POSITION. PLACE ELEMENT
+C           IN POSITION AND MAKE THE DISPLACED ELEMENT THE
+C           CURRENT ELEMENT.
+C
+            L = IWA(J)
+            IWA(J) = IWA(J) + 1
+            I = INDROW(K)
+            INDROW(K) = INDROW(L)
+            INDCOL(K) = INDCOL(L)
+            INDROW(L) = I
+            INDCOL(L) = J
+   60    CONTINUE
+         IF (K .LE. NNZ) GO TO 40
+      RETURN
+C
+C     LAST CARD OF SUBROUTINE S7RTDT.
+C
+      END
+      SUBROUTINE DL7SRT(N1, N, L, A, IRC)
+C
+C  ***  COMPUTE ROWS N1 THROUGH N OF THE CHOLESKY FACTOR  L  OF
+C  ***  A = L*(L**T),  WHERE  L  AND THE LOWER TRIANGLE OF  A  ARE BOTH
+C  ***  STORED COMPACTLY BY ROWS (AND MAY OCCUPY THE SAME STORAGE).
+C  ***  IRC = 0 MEANS ALL WENT WELL.  IRC = J MEANS THE LEADING
+C  ***  PRINCIPAL  J X J  SUBMATRIX OF  A  IS NOT POSITIVE DEFINITE --
+C  ***  AND  L(J*(J+1)/2)  CONTAINS THE (NONPOS.) REDUCED J-TH DIAGONAL.
+C
+C  ***  PARAMETERS  ***
+C
+      INTEGER N1, N, IRC
+      DOUBLE PRECISION L(*), A(*)
+C     DIMENSION L(N*(N+1)/2), A(N*(N+1)/2)
+C
+C  ***  LOCAL VARIABLES  ***
+C
+      INTEGER I, IJ, IK, IM1, I0, J, JK, JM1, J0, K
+      DOUBLE PRECISION T, TD, ZERO
+C
+C  ***  INTRINSIC FUNCTIONS  ***
+C/+
+      DOUBLE PRECISION DSQRT
+C/
+      PARAMETER (ZERO=0.D+0)
+C
+C  ***  BODY  ***
+C
+      I0 = N1 * (N1 - 1) / 2
+      DO 50 I = N1, N
+         TD = ZERO
+         IF (I .EQ. 1) GO TO 40
+         J0 = 0
+         IM1 = I - 1
+         DO 30 J = 1, IM1
+              T = ZERO
+              IF (J .EQ. 1) GO TO 20
+              JM1 = J - 1
+              DO 10 K = 1, JM1
+                   IK = I0 + K
+                   JK = J0 + K
+                   T = T + L(IK)*L(JK)
+ 10                CONTINUE
+ 20           IJ = I0 + J
+              J0 = J0 + J
+              T = (A(IJ) - T) / L(J0)
+              L(IJ) = T
+              TD = TD + T*T
+ 30           CONTINUE
+ 40      I0 = I0 + I
+         T = A(I0) - TD
+         IF (T .LE. ZERO) GO TO 60
+         L(I0) = DSQRT(T)
+ 50      CONTINUE
+C
+      IRC = 0
+      GO TO 999
+C
+ 60   L(I0) = T
+      IRC = I
+C
+ 999  RETURN
+C
+C  ***  LAST CARD OF DL7SRT  ***
+      END
+      DOUBLE PRECISION FUNCTION DL7SVN(P, L, X, Y)
+C
+C  ***  ESTIMATE SMALLEST SING. VALUE OF PACKED LOWER TRIANG. MATRIX L
+C
+C  ***  PARAMETER DECLARATIONS  ***
+C
+      INTEGER P
+      DOUBLE PRECISION L(*), X(P), Y(P)
+C     DIMENSION L(P*(P+1)/2)
+C
+C+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+C
+C  ***  PURPOSE  ***
+C
+C     THIS FUNCTION RETURNS A GOOD OVER-ESTIMATE OF THE SMALLEST
+C     SINGULAR VALUE OF THE PACKED LOWER TRIANGULAR MATRIX L.
+C
+C  ***  PARAMETER DESCRIPTION  ***
+C
+C  P (IN)  = THE ORDER OF L.  L IS A  P X P  LOWER TRIANGULAR MATRIX.
+C  L (IN)  = ARRAY HOLDING THE ELEMENTS OF  L  IN ROW ORDER, I.E.
+C             L(1,1), L(2,1), L(2,2), L(3,1), L(3,2), L(3,3), ETC.
+C  X (OUT) IF DL7SVN RETURNS A POSITIVE VALUE, THEN X IS A NORMALIZED
+C             APPROXIMATE LEFT SINGULAR VECTOR CORRESPONDING TO THE
+C             SMALLEST SINGULAR VALUE.  THIS APPROXIMATION MAY BE VERY
+C             CRUDE.  IF DL7SVN RETURNS ZERO, THEN SOME COMPONENTS OF X
+C             ARE ZERO AND THE REST RETAIN THEIR INPUT VALUES.
+C  Y (OUT) IF DL7SVN RETURNS A POSITIVE VALUE, THEN Y = (L**-1)*X IS AN
+C             UNNORMALIZED APPROXIMATE RIGHT SINGULAR VECTOR CORRESPOND-
+C             ING TO THE SMALLEST SINGULAR VALUE.  THIS APPROXIMATION
+C             MAY BE CRUDE.  IF DL7SVN RETURNS ZERO, THEN Y RETAINS ITS
+C             INPUT VALUE.  THE CALLER MAY PASS THE SAME VECTOR FOR X
+C             AND Y (NONSTANDARD FORTRAN USAGE), IN WHICH CASE Y OVER-
+C             WRITES X (FOR NONZERO DL7SVN RETURNS).
+C
+C  ***  ALGORITHM NOTES  ***
+C
+C     THE ALGORITHM IS BASED ON (1), WITH THE ADDITIONAL PROVISION THAT
+C     DL7SVN = 0 IS RETURNED IF THE SMALLEST DIAGONAL ELEMENT OF L
+C     (IN MAGNITUDE) IS NOT MORE THAN THE UNIT ROUNDOFF TIMES THE
+C     LARGEST.  THE ALGORITHM USES A RANDOM NUMBER GENERATOR PROPOSED
+C     IN (4), WHICH PASSES THE SPECTRAL TEST WITH FLYING COLORS -- SEE
+C     (2) AND (3).
+C
+C  ***  SUBROUTINES AND FUNCTIONS CALLED  ***
+C
+C        DV2NRM - FUNCTION, RETURNS THE 2-NORM OF A VECTOR.
+C
+C  ***  REFERENCES  ***
+C
+C     (1) CLINE, A., MOLER, C., STEWART, G., AND WILKINSON, J.H.(1977),
+C         AN ESTIMATE FOR THE CONDITION NUMBER OF A MATRIX, REPORT
+C         TM-310, APPLIED MATH. DIV., ARGONNE NATIONAL LABORATORY.
+C
+C     (2) HOAGLIN, D.C. (1976), THEORETICAL PROPERTIES OF CONGRUENTIAL
+C         RANDOM-NUMBER GENERATORS --  AN EMPIRICAL VIEW,
+C         MEMORANDUM NS-340, DEPT. OF STATISTICS, HARVARD UNIV.
+C
+C     (3) KNUTH, D.E. (1969), THE ART OF COMPUTER PROGRAMMING, VOL. 2
+C         (SEMINUMERICAL ALGORITHMS), ADDISON-WESLEY, READING, MASS.
+C
+C     (4) SMITH, C.S. (1971), MULTIPLICATIVE PSEUDO-RANDOM NUMBER
+C         GENERATORS WITH PRIME MODULUS, J. ASSOC. COMPUT. MACH. 18,
+C         PP. 586-593.
+C
+C  ***  HISTORY  ***
+C
+C     DESIGNED AND CODED BY DAVID M. GAY (WINTER 1977/SUMMER 1978).
+C
+C  ***  GENERAL  ***
+C
+C     THIS SUBROUTINE WAS WRITTEN IN CONNECTION WITH RESEARCH
+C     SUPPORTED BY THE NATIONAL SCIENCE FOUNDATION UNDER GRANTS
+C     MCS-7600324, DCR75-10143, 76-14311DSS, AND MCS76-11989.
+C
+C+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+C
+C  ***  LOCAL VARIABLES  ***
+C
+      INTEGER I, II, IX, J, JI, JJ, JJJ, JM1, J0, PM1
+      DOUBLE PRECISION B, SMINUS, SPLUS, T, XMINUS, XPLUS
+C
+C  ***  CONSTANTS  ***
+C
+      DOUBLE PRECISION HALF, ONE, R9973, ZERO
+C
+C  ***  EXTERNAL FUNCTIONS AND SUBROUTINES  ***
+C
+      DOUBLE PRECISION DD7TPR, DV2NRM
+      EXTERNAL DD7TPR, DV2NRM,DV2AXY
+C
+      PARAMETER (HALF=0.5D+0, ONE=1.D+0, R9973=9973.D+0, ZERO=0.D+0)
+C
+C  ***  BODY  ***
+C
+      IX = 2
+      PM1 = P - 1
+C
+C  ***  FIRST CHECK WHETHER TO RETURN DL7SVN = 0 AND INITIALIZE X  ***
+C
+      II = 0
+      J0 = P*PM1/2
+      JJ = J0 + P
+      IF (L(JJ) .EQ. ZERO) GO TO 110
+      IX = MOD(3432*IX, 9973)
+      B = HALF*(ONE + DBLE(IX)/R9973)
+      XPLUS = B / L(JJ)
+      X(P) = XPLUS
+      IF (P .LE. 1) GO TO 60
+      DO 10 I = 1, PM1
+         II = II + I
+         IF (L(II) .EQ. ZERO) GO TO 110
+         JI = J0 + I
+         X(I) = XPLUS * L(JI)
+ 10      CONTINUE
+C
+C  ***  SOLVE (L**T)*X = B, WHERE THE COMPONENTS OF B HAVE RANDOMLY
+C  ***  CHOSEN MAGNITUDES IN (.5,1) WITH SIGNS CHOSEN TO MAKE X LARGE.
+C
+C     DO J = P-1 TO 1 BY -1...
+      DO 50 JJJ = 1, PM1
+         J = P - JJJ
+C       ***  DETERMINE X(J) IN THIS ITERATION. NOTE FOR I = 1,2,...,J
+C       ***  THAT X(I) HOLDS THE CURRENT PARTIAL SUM FOR ROW I.
+         IX = MOD(3432*IX, 9973)
+         B = HALF*(ONE + DBLE(IX)/R9973)
+         XPLUS = (B - X(J))
+         XMINUS = (-B - X(J))
+         SPLUS = DABS(XPLUS)
+         SMINUS = DABS(XMINUS)
+         JM1 = J - 1
+         J0 = J*JM1/2
+         JJ = J0 + J
+         XPLUS = XPLUS/L(JJ)
+         XMINUS = XMINUS/L(JJ)
+         IF (JM1 .EQ. 0) GO TO 30
+         DO 20 I = 1, JM1
+              JI = J0 + I
+              SPLUS = SPLUS + DABS(X(I) + L(JI)*XPLUS)
+              SMINUS = SMINUS + DABS(X(I) + L(JI)*XMINUS)
+ 20           CONTINUE
+ 30      IF (SMINUS .GT. SPLUS) XPLUS = XMINUS
+         X(J) = XPLUS
+C       ***  UPDATE PARTIAL SUMS  ***
+         IF (JM1 .GT. 0) CALL DV2AXY(JM1, X, XPLUS, L(J0+1), X)
+ 50      CONTINUE
+C
+C  ***  NORMALIZE X  ***
+C
+ 60   T = ONE/DV2NRM(P, X)
+      DO 70 I = 1, P
+ 70      X(I) = T*X(I)
+C
+C  ***  SOLVE L*Y = X AND RETURN DL7SVN = 1/TWONORM(Y)  ***
+C
+      DO 100 J = 1, P
+         JM1 = J - 1
+         J0 = J*JM1/2
+         JJ = J0 + J
+         T = ZERO
+         IF (JM1 .GT. 0) T = DD7TPR(JM1, L(J0+1), Y)
+         Y(J) = (X(J) - T) / L(JJ)
+ 100     CONTINUE
+C
+      DL7SVN = ONE/DV2NRM(P, Y)
+      GO TO 999
+C
+ 110  DL7SVN = ZERO
+ 999  RETURN
+C  ***  LAST CARD OF DL7SVN FOLLOWS  ***
+      END
+      SUBROUTINE DS7LVM(P, Y, S, X)
+C
+C  ***  SET  Y = S * X,  S = P X P SYMMETRIC MATRIX.  ***
+C  ***  LOWER TRIANGLE OF  S  STORED ROWWISE.         ***
+C
+C  ***  PARAMETER DECLARATIONS  ***
+C
+      INTEGER P
+      DOUBLE PRECISION S(*), X(P), Y(P)
+C     DIMENSION S(P*(P+1)/2)
+C
+C  ***  LOCAL VARIABLES  ***
+C
+      INTEGER I, IM1, J, K
+      DOUBLE PRECISION XI
+C
+C  ***  NO INTRINSIC FUNCTIONS  ***
+C
+C  ***  EXTERNAL FUNCTION  ***
+C
+      DOUBLE PRECISION DD7TPR
+      EXTERNAL DD7TPR
+C
+C-----------------------------------------------------------------------
+C
+      J = 1
+      DO 10 I = 1, P
+         Y(I) = DD7TPR(I, S(J), X)
+         J = J + I
+ 10      CONTINUE
+C
+      IF (P .LE. 1) GO TO 999
+      J = 1
+      DO 40 I = 2, P
+         XI = X(I)
+         IM1 = I - 1
+         J = J + 1
+         DO 30 K = 1, IM1
+              Y(K) = Y(K) + S(J)*XI
+              J = J + 1
+ 30           CONTINUE
+ 40      CONTINUE
+C
+ 999  RETURN
+C  ***  LAST CARD OF DS7LVM FOLLOWS  ***
+      END
+      DOUBLE PRECISION FUNCTION DH2RFG(A, B, X, Y, Z)
+C
+C  ***  DETERMINE X, Y, Z SO  I + (1,Z)**T * (X,Y)  IS A 2X2
+C  ***  HOUSEHOLDER REFLECTION SENDING (A,B)**T INTO (C,0)**T,
+C  ***  WHERE  C = -SIGN(A)*SQRT(A**2 + B**2)  IS THE VALUE DH2RFG
+C  ***  RETURNS.
+C
+      DOUBLE PRECISION A, B, X, Y, Z
+C
+      DOUBLE PRECISION A1, B1, C, T
+C/+
+      DOUBLE PRECISION DSQRT
+C/
+      DOUBLE PRECISION ZERO
+      DATA ZERO/0.D+0/
+C
+C  ***  BODY  ***
+C
+      IF (B .NE. ZERO) GO TO 10
+         X = ZERO
+         Y = ZERO
+         Z = ZERO
+         DH2RFG = A
+         GO TO 999
+ 10   T = DABS(A) + DABS(B)
+      A1 = A / T
+      B1 = B / T
+      C = DSQRT(A1**2 + B1**2)
+      IF (A1 .GT. ZERO) C = -C
+      A1 = A1 - C
+      Z = B1 / A1
+      X = A1 / C
+      Y = B1 / C
+      DH2RFG = T * C
+ 999  RETURN
+C  ***  LAST LINE OF DH2RFG FOLLOWS  ***
+      END
+      SUBROUTINE DL7NVR(N, LIN, L)
+C
+C  ***  COMPUTE  LIN = L**-1,  BOTH  N X N  LOWER TRIANG. STORED   ***
+C  ***  COMPACTLY BY ROWS.  LIN AND L MAY SHARE THE SAME STORAGE.  ***
+C
+C  ***  PARAMETERS  ***
+C
+      INTEGER N
+      DOUBLE PRECISION L(*), LIN(*)
+C     DIMENSION L(N*(N+1)/2), LIN(N*(N+1)/2)
+C
+C  ***  LOCAL VARIABLES  ***
+C
+      INTEGER I, II, IM1, JJ, J0, J1, K, K0, NP1
+      DOUBLE PRECISION ONE, T, ZERO
+      PARAMETER (ONE=1.D+0, ZERO=0.D+0)
+C
+C  ***  BODY  ***
+C
+      NP1 = N + 1
+      J0 = N*NP1/2
+      DO 30 II = 1, N
+         I = NP1 - II
+         LIN(J0) = ONE/L(J0)
+         IF (I .LE. 1) GO TO 999
+         J1 = J0
+         IM1 = I - 1
+         DO 20 JJ = 1, IM1
+              T = ZERO
+              J0 = J1
+              K0 = J1 - JJ
+              DO 10 K = 1, JJ
+                   T = T - L(K0)*LIN(J0)
+                   J0 = J0 - 1
+                   K0 = K0 + K - I
+ 10                CONTINUE
+              LIN(J0) = T/L(K0)
+ 20           CONTINUE
+         J0 = J0 - 1
+ 30      CONTINUE
+ 999  RETURN
+C  ***  LAST CARD OF DL7NVR FOLLOWS  ***
+      END
+      SUBROUTINE DD7DOG(DIG, LV, N, NWTSTP, STEP, V)
+C
+C  ***  COMPUTE DOUBLE DOGLEG STEP  ***
+C
+C  ***  PARAMETER DECLARATIONS  ***
+C
+      INTEGER LV, N
+      DOUBLE PRECISION DIG(N), NWTSTP(N), STEP(N), V(LV)
+C
+C  ***  PURPOSE  ***
+C
+C        THIS SUBROUTINE COMPUTES A CANDIDATE STEP (FOR USE IN AN UNCON-
+C     STRAINED MINIMIZATION CODE) BY THE DOUBLE DOGLEG ALGORITHM OF
+C     DENNIS AND MEI (REF. 1), WHICH IS A VARIATION ON POWELL*S DOGLEG
+C     SCHEME (REF. 2, P. 95).
+C
+C--------------------------  PARAMETER USAGE  --------------------------
+C
+C    DIG (INPUT) DIAG(D)**-2 * G -- SEE ALGORITHM NOTES.
+C      G (INPUT) THE CURRENT GRADIENT VECTOR.
+C     LV (INPUT) LENGTH OF V.
+C      N (INPUT) NUMBER OF COMPONENTS IN  DIG, G, NWTSTP,  AND  STEP.
+C NWTSTP (INPUT) NEGATIVE NEWTON STEP -- SEE ALGORITHM NOTES.
+C   STEP (OUTPUT) THE COMPUTED STEP.
+C      V (I/O) VALUES ARRAY, THE FOLLOWING COMPONENTS OF WHICH ARE
+C             USED HERE...
+C V(BIAS)   (INPUT) BIAS FOR RELAXED NEWTON STEP, WHICH IS V(BIAS) OF
+C             THE WAY FROM THE FULL NEWTON TO THE FULLY RELAXED NEWTON
+C             STEP.  RECOMMENDED VALUE = 0.8 .
+C V(DGNORM) (INPUT) 2-NORM OF DIAG(D)**-1 * G -- SEE ALGORITHM NOTES.
+C V(DSTNRM) (OUTPUT) 2-NORM OF DIAG(D) * STEP, WHICH IS V(RADIUS)
+C             UNLESS V(STPPAR) = 0 -- SEE ALGORITHM NOTES.
+C V(DST0) (INPUT) 2-NORM OF DIAG(D) * NWTSTP -- SEE ALGORITHM NOTES.
+C V(GRDFAC) (OUTPUT) THE COEFFICIENT OF  DIG  IN THE STEP RETURNED --
+C             STEP(I) = V(GRDFAC)*DIG(I) + V(NWTFAC)*NWTSTP(I).
+C V(GTHG)   (INPUT) SQUARE-ROOT OF (DIG**T) * (HESSIAN) * DIG -- SEE
+C             ALGORITHM NOTES.
+C V(GTSTEP) (OUTPUT) INNER PRODUCT BETWEEN G AND STEP.
+C V(NREDUC) (OUTPUT) FUNCTION REDUCTION PREDICTED FOR THE FULL NEWTON
+C             STEP.
+C V(NWTFAC) (OUTPUT) THE COEFFICIENT OF  NWTSTP  IN THE STEP RETURNED --
+C             SEE V(GRDFAC) ABOVE.
+C V(PREDUC) (OUTPUT) FUNCTION REDUCTION PREDICTED FOR THE STEP RETURNED.
+C V(RADIUS) (INPUT) THE TRUST REGION RADIUS.  D TIMES THE STEP RETURNED
+C             HAS 2-NORM V(RADIUS) UNLESS V(STPPAR) = 0.
+C V(STPPAR) (OUTPUT) CODE TELLING HOW STEP WAS COMPUTED... 0 MEANS A
+C             FULL NEWTON STEP.  BETWEEN 0 AND 1 MEANS V(STPPAR) OF THE
+C             WAY FROM THE NEWTON TO THE RELAXED NEWTON STEP.  BETWEEN
+C             1 AND 2 MEANS A TRUE DOUBLE DOGLEG STEP, V(STPPAR) - 1 OF
+C             THE WAY FROM THE RELAXED NEWTON TO THE CAUCHY STEP.
+C             GREATER THAN 2 MEANS 1 / (V(STPPAR) - 1) TIMES THE CAUCHY
+C             STEP.
+C
+C-------------------------------  NOTES  -------------------------------
+C
+C  ***  ALGORITHM NOTES  ***
+C
+C        LET  G  AND  H  BE THE CURRENT GRADIENT AND HESSIAN APPROXIMA-
+C     TION RESPECTIVELY AND LET D BE THE CURRENT SCALE VECTOR.  THIS
+C     ROUTINE ASSUMES DIG = DIAG(D)**-2 * G  AND  NWTSTP = H**-1 * G.
+C     THE STEP COMPUTED IS THE SAME ONE WOULD GET BY REPLACING G AND H
+C     BY  DIAG(D)**-1 * G  AND  DIAG(D)**-1 * H * DIAG(D)**-1,
+C     COMPUTING STEP, AND TRANSLATING STEP BACK TO THE ORIGINAL
+C     VARIABLES, I.E., PREMULTIPLYING IT BY DIAG(D)**-1.
+C
+C  ***  REFERENCES  ***
+C
+C 1.  DENNIS, J.E., AND MEI, H.H.W. (1979), TWO NEW UNCONSTRAINED OPTI-
+C             MIZATION ALGORITHMS WHICH USE FUNCTION AND GRADIENT
+C             VALUES, J. OPTIM. THEORY APPLIC. 28, PP. 453-482.
+C 2. POWELL, M.J.D. (1970), A HYBRID METHOD FOR NON-LINEAR EQUATIONS,
+C             IN NUMERICAL METHODS FOR NON-LINEAR EQUATIONS, EDITED BY
+C             P. RABINOWITZ, GORDON AND BREACH, LONDON.
+C
+C  ***  GENERAL  ***
+C
+C     CODED BY DAVID M. GAY.
+C     THIS SUBROUTINE WAS WRITTEN IN CONNECTION WITH RESEARCH SUPPORTED
+C     BY THE NATIONAL SCIENCE FOUNDATION UNDER GRANTS MCS-7600324 AND
+C     MCS-7906671.
+C
+C------------------------  EXTERNAL QUANTITIES  ------------------------
+C
+C  ***  INTRINSIC FUNCTIONS  ***
+C/+
+      DOUBLE PRECISION DSQRT
+C/
+C--------------------------  LOCAL VARIABLES  --------------------------
+C
+      INTEGER I
+      DOUBLE PRECISION CFACT, CNORM, CTRNWT, GHINVG, FEMNSQ, GNORM,
+     1                 NWTNRM, RELAX, RLAMBD, T, T1, T2
+      DOUBLE PRECISION HALF, ONE, TWO, ZERO
+C
+C  ***  V SUBSCRIPTS  ***
+C
+      INTEGER BIAS, DGNORM, DSTNRM, DST0, GRDFAC, GTHG, GTSTEP,
+     1        NREDUC, NWTFAC, PREDUC, RADIUS, STPPAR
+C
+C  ***  DATA INITIALIZATIONS  ***
+C
+      PARAMETER (HALF=0.5D+0, ONE=1.D+0, TWO=2.D+0, ZERO=0.D+0)
+C
+      PARAMETER (BIAS=43, DGNORM=1, DSTNRM=2, DST0=3, GRDFAC=45,
+     1           GTHG=44, GTSTEP=4, NREDUC=6, NWTFAC=46, PREDUC=7,
+     2           RADIUS=8, STPPAR=5)
+C
+C+++++++++++++++++++++++++++++++  BODY  ++++++++++++++++++++++++++++++++
+C
+      NWTNRM = V(DST0)
+      RLAMBD = ONE
+      IF (NWTNRM .GT. ZERO) RLAMBD = V(RADIUS) / NWTNRM
+      GNORM = V(DGNORM)
+      GHINVG = TWO * V(NREDUC)
+      V(GRDFAC) = ZERO
+      V(NWTFAC) = ZERO
+      IF (RLAMBD .LT. ONE) GO TO 30
+C
+C        ***  THE NEWTON STEP IS INSIDE THE TRUST REGION  ***
+C
+         V(STPPAR) = ZERO
+         V(DSTNRM) = NWTNRM
+         V(GTSTEP) = -GHINVG
+         V(PREDUC) = V(NREDUC)
+         V(NWTFAC) = -ONE
+         DO 20 I = 1, N
+ 20           STEP(I) = -NWTSTP(I)
+         GO TO 999
+C
+ 30   V(DSTNRM) = V(RADIUS)
+      CFACT = (GNORM / V(GTHG))**2
+C     ***  CAUCHY STEP = -CFACT * G.
+      CNORM = GNORM * CFACT
+      RELAX = ONE - V(BIAS) * (ONE - GNORM*CNORM/GHINVG)
+      IF (RLAMBD .LT. RELAX) GO TO 50
+C
+C        ***  STEP IS BETWEEN RELAXED NEWTON AND FULL NEWTON STEPS  ***
+C
+         V(STPPAR)  =  ONE  -  (RLAMBD - RELAX) / (ONE - RELAX)
+         T = -RLAMBD
+         V(GTSTEP) = T * GHINVG
+         V(PREDUC) = RLAMBD * (ONE - HALF*RLAMBD) * GHINVG
+         V(NWTFAC) = T
+         DO 40 I = 1, N
+ 40           STEP(I) = T * NWTSTP(I)
+         GO TO 999
+C
+ 50   IF (CNORM .LT. V(RADIUS)) GO TO 70
+C
+C        ***  THE CAUCHY STEP LIES OUTSIDE THE TRUST REGION --
+C        ***  STEP = SCALED CAUCHY STEP  ***
+C
+         T = -V(RADIUS) / GNORM
+         V(GRDFAC) = T
+         V(STPPAR) = ONE  +  CNORM / V(RADIUS)
+         V(GTSTEP) = -V(RADIUS) * GNORM
+      V(PREDUC) = V(RADIUS)*(GNORM - HALF*V(RADIUS)*(V(GTHG)/GNORM)**2)
+         DO 60 I = 1, N
+ 60           STEP(I) = T * DIG(I)
+         GO TO 999
+C
+C     ***  COMPUTE DOGLEG STEP BETWEEN CAUCHY AND RELAXED NEWTON  ***
+C     ***  FEMUR = RELAXED NEWTON STEP MINUS CAUCHY STEP  ***
+C
+ 70   CTRNWT = CFACT * RELAX * GHINVG / GNORM
+C     *** CTRNWT = INNER PROD. OF CAUCHY AND RELAXED NEWTON STEPS,
+C     *** SCALED BY GNORM**-1.
+      T1 = CTRNWT - GNORM*CFACT**2
+C     ***  T1 = INNER PROD. OF FEMUR AND CAUCHY STEP, SCALED BY
+C     ***  GNORM**-1.
+      T2 = V(RADIUS)*(V(RADIUS)/GNORM) - GNORM*CFACT**2
+      T = RELAX * NWTNRM
+      FEMNSQ = (T/GNORM)*T - CTRNWT - T1
+C     ***  FEMNSQ = SQUARE OF 2-NORM OF FEMUR, SCALED BY GNORM**-1.
+      T = T2 / (T1 + DSQRT(T1**2 + FEMNSQ*T2))
+C     ***  DOGLEG STEP  =  CAUCHY STEP  +  T * FEMUR.
+      T1 = (T - ONE) * CFACT
+      V(GRDFAC) = T1
+      T2 = -T * RELAX
+      V(NWTFAC) = T2
+      V(STPPAR) = TWO - T
+      V(GTSTEP) = T1*GNORM**2 + T2*GHINVG
+      V(PREDUC) = -T1*GNORM * ((T2 + ONE)*GNORM)
+     1                 - T2 * (ONE + HALF*T2)*GHINVG
+     2                  - HALF * (V(GTHG)*T1)**2
+      DO 80 I = 1, N
+ 80      STEP(I) = T1*DIG(I) + T2*NWTSTP(I)
+C
+ 999  RETURN
+C  ***  LAST LINE OF DD7DOG FOLLOWS  ***
+      END
+      SUBROUTINE DS7IPR(P, IP, H)
+C
+C  APPLY THE PERMUTATION DEFINED BY IP TO THE ROWS AND COLUMNS OF THE
+C  P X P SYMMETRIC MATRIX WHOSE LOWER TRIANGLE IS STORED COMPACTLY IN H.
+C  THUS H.OUTPUT(I,J) = H.INPUT(IP(I), IP(J)).
+C
+      INTEGER P
+      INTEGER IP(P)
+      DOUBLE PRECISION H(*)
+C
+      INTEGER I, J, J1, JM, K, K1, KK, KM, KMJ, L, M
+      DOUBLE PRECISION T
+C
+C ***  BODY  ***
+C
+      DO 90 I = 1, P
+         J = IP(I)
+         IF (J .EQ. I) GO TO 90
+         IP(I) = IABS(J)
+         IF (J .LT. 0) GO TO 90
+         K = I
+ 10         J1 = J
+            K1 = K
+            IF (J .LE. K) GO TO 20
+               J1 = K
+               K1 = J
+ 20         KMJ = K1-J1
+            L = J1-1
+            JM = J1*L/2
+            KM = K1*(K1-1)/2
+            IF (L .LE. 0) GO TO 40
+               DO 30 M = 1, L
+                  JM = JM+1
+                  T = H(JM)
+                  KM = KM+1
+                  H(JM) = H(KM)
+                  H(KM) = T
+ 30               CONTINUE
+ 40         KM = KM+1
+            KK = KM+KMJ
+            JM = JM+1
+            T = H(JM)
+            H(JM) = H(KK)
+            H(KK) = T
+            J1 = L
+            L = KMJ-1
+            IF (L .LE. 0) GO TO 60
+               DO 50 M = 1, L
+                  JM = JM+J1+M
+                  T = H(JM)
+                  KM = KM+1
+                  H(JM) = H(KM)
+                  H(KM) = T
+ 50               CONTINUE
+ 60         IF (K1 .GE. P) GO TO 80
+               L = P-K1
+               K1 = K1-1
+               KM = KK
+               DO 70 M = 1, L
+                  KM = KM+K1+M
+                  JM = KM-KMJ
+                  T = H(JM)
+                  H(JM) = H(KM)
+                  H(KM) = T
+ 70               CONTINUE
+ 80         K = J
+            J = IP(K)
+            IP(K) = -J
+            IF (J .GT. I) GO TO 10
+ 90      CONTINUE
+      RETURN
+C  ***  LAST LINE OF DS7IPR FOLLOWS  ***
+      END
+      SUBROUTINE DH2RFA(N, A, B, X, Y, Z)
+C
+C  ***  APPLY 2X2 HOUSEHOLDER REFLECTION DETERMINED BY X, Y, Z TO
+C  ***  N-VECTORS A, B  ***
+C
+      INTEGER N
+      DOUBLE PRECISION A(N), B(N), X, Y, Z
+      INTEGER I
+      DOUBLE PRECISION T
+      DO 10 I = 1, N
+         T = A(I)*X + B(I)*Y
+         A(I) = A(I) + T
+         B(I) = B(I) + T*Z
+ 10      CONTINUE
+      RETURN
+C  ***  LAST LINE OF DH2RFA FOLLOWS  ***
+      END
+      SUBROUTINE DPARCK(ALG, D, IV, LIV, LV, N, V)
+C
+C  ***  CHECK ***SOL (VERSION 2.3) PARAMETERS, PRINT CHANGED VALUES  ***
+C
+C  ***  ALG = 1 FOR REGRESSION, ALG = 2 FOR GENERAL UNCONSTRAINED OPT.
+C
+      INTEGER ALG, LIV, LV, N
+      INTEGER IV(LIV)
+      DOUBLE PRECISION D(N), V(LV)
+C
+      DOUBLE PRECISION DR7MDC
+      EXTERNAL DIVSET, DR7MDC,DV7CPY,DV7DFL
+C DIVSET  -- SUPPLIES DEFAULT VALUES TO BOTH IV AND V.
+C DR7MDC -- RETURNS MACHINE-DEPENDENT CONSTANTS.
+C DV7CPY  -- COPIES ONE VECTOR TO ANOTHER.
+C DV7DFL  -- SUPPLIES DEFAULT PARAMETER VALUES TO V ALONE.
+C
+C  ***  LOCAL VARIABLES  ***
+C
+      INTEGER ALG1, I, II, IV1, J, K, L, M, MIV1, MIV2, NDFALT, PARSV1,
+     1        PU
+      INTEGER IJMP, JLIM(4), MINIV(4), NDFLT(4)
+      CHARACTER*4 CNGD(3), DFLT(3), WHICH(3)
+      DOUBLE PRECISION BIG, MACHEP, TINY, VK, VM(34), VX(34), ZERO
+C
+C  ***  IV AND V SUBSCRIPTS  ***
+C
+      INTEGER ALGSAV, DINIT, DTYPE, DTYPE0, EPSLON, INITS, IVNEED,
+     1        LASTIV, LASTV, LMAT, NEXTIV, NEXTV, NVDFLT, OLDN,
+     2        PARPRT, PARSAV, PERM, PRUNIT, VNEED
+C
+C
+      PARAMETER (ALGSAV=51, DINIT=38, DTYPE=16, DTYPE0=54, EPSLON=19,
+     1           INITS=25, IVNEED=3, LASTIV=44, LASTV=45, LMAT=42,
+     2           NEXTIV=46, NEXTV=47, NVDFLT=50, OLDN=38, PARPRT=20,
+     3           PARSAV=49, PERM=58, PRUNIT=21, VNEED=4)
+      SAVE BIG, MACHEP, TINY
+C
+      DATA BIG/0.D+0/, MACHEP/-1.D+0/, TINY/1.D+0/, ZERO/0.D+0/
+C
+      DATA VM(1)/1.0D-3/, VM(2)/-0.99D+0/, VM(3)/1.0D-3/, VM(4)/1.0D-2/,
+     1     VM(5)/1.2D+0/, VM(6)/1.D-2/, VM(7)/1.2D+0/, VM(8)/0.D+0/,
+     2     VM(9)/0.D+0/, VM(10)/1.D-3/, VM(11)/-1.D+0/, VM(13)/0.D+0/,
+     3     VM(15)/0.D+0/, VM(16)/0.D+0/, VM(19)/0.D+0/, VM(20)/-10.D+0/,
+     4     VM(21)/0.D+0/, VM(22)/0.D+0/, VM(23)/0.D+0/, VM(27)/1.01D+0/,
+     5     VM(28)/1.D+10/, VM(30)/0.D+0/, VM(31)/0.D+0/, VM(32)/0.D+0/,
+     6     VM(34)/0.D+0/
+      DATA VX(1)/0.9D+0/, VX(2)/-1.D-3/, VX(3)/1.D+1/, VX(4)/0.8D+0/,
+     1     VX(5)/1.D+2/, VX(6)/0.8D+0/, VX(7)/1.D+2/, VX(8)/0.5D+0/,
+     2     VX(9)/0.5D+0/, VX(10)/1.D+0/, VX(11)/1.D+0/, VX(14)/0.1D+0/,
+     3     VX(15)/1.D+0/, VX(16)/1.D+0/, VX(19)/1.D+0/, VX(23)/1.D+0/,
+     4     VX(24)/1.D+0/, VX(25)/1.D+0/, VX(26)/1.D+0/, VX(27)/1.D+10/,
+     5     VX(29)/1.D+0/, VX(31)/1.D+0/, VX(32)/1.D+0/, VX(33)/1.D+0/,
+     6     VX(34)/1.D+0/
+C
+      DATA CNGD(1),CNGD(2),CNGD(3)/'---C','HANG','ED V'/,
+     1     DFLT(1),DFLT(2),DFLT(3)/'NOND','EFAU','LT V'/
+      DATA IJMP/33/, JLIM(1)/0/, JLIM(2)/24/, JLIM(3)/0/, JLIM(4)/24/,
+     1     NDFLT(1)/32/, NDFLT(2)/25/, NDFLT(3)/32/, NDFLT(4)/25/
+      DATA MINIV(1)/82/, MINIV(2)/59/, MINIV(3)/103/, MINIV(4)/103/
+C
+C...............................  BODY  ................................
+C
+      PU = 0
+      IF (PRUNIT .LE. LIV) PU = IV(PRUNIT)
+      IF (ALGSAV .GT. LIV) GO TO 20
+      IF (ALG .EQ. IV(ALGSAV)) GO TO 20
+C         IF (PU .NE. 0) WRITE(PU,10) ALG, IV(ALGSAV)
+C 10      FORMAT(/40H THE FIRST PARAMETER TO DIVSET SHOULD BE,I3,
+C     1          12H RATHER THAN,I3)
+         IV(1) = 67
+         GO TO 999
+ 20   IF (ALG .LT. 1 .OR. ALG .GT. 4) GO TO 340
+      MIV1 = MINIV(ALG)
+      IF (IV(1) .EQ. 15) GO TO 360
+      ALG1 = MOD(ALG-1,2) + 1
+      IF (IV(1) .EQ. 0) CALL DIVSET(ALG, IV, LIV, LV, V)
+      IV1 = IV(1)
+      IF (IV1 .NE. 13 .AND. IV1 .NE. 12) GO TO 30
+      IF (PERM .LE. LIV) MIV1 = MAX0(MIV1, IV(PERM) - 1)
+      IF (IVNEED .LE. LIV) MIV2 = MIV1 + MAX0(IV(IVNEED), 0)
+      IF (LASTIV .LE. LIV) IV(LASTIV) = MIV2
+      IF (LIV .LT. MIV1) GO TO 300
+      IV(IVNEED) = 0
+      IV(LASTV) = MAX0(IV(VNEED), 0) + IV(LMAT) - 1
+      IV(VNEED) = 0
+      IF (LIV .LT. MIV2) GO TO 300
+      IF (LV .LT. IV(LASTV)) GO TO 320
+ 30   IF (IV1 .LT. 12 .OR. IV1 .GT. 14) GO TO 60
+         IF (N .GE. 1) GO TO 50
+              IV(1) = 81
+              IF (PU .EQ. 0) GO TO 999
+C              WRITE(PU,40) VARNM(ALG1), N
+C 40           FORMAT(/8H /// BAD,A1,2H =,I5)
+              GO TO 999
+ 50      IF (IV1 .NE. 14) IV(NEXTIV) = IV(PERM)
+         IF (IV1 .NE. 14) IV(NEXTV) = IV(LMAT)
+         IF (IV1 .EQ. 13) GO TO 999
+         K = IV(PARSAV) - EPSLON
+         CALL DV7DFL(ALG1, LV-K, V(K+1))
+         IV(DTYPE0) = 2 - ALG1
+         IV(OLDN) = N
+         WHICH(1) = DFLT(1)
+         WHICH(2) = DFLT(2)
+         WHICH(3) = DFLT(3)
+         GO TO 110
+ 60   IF (N .EQ. IV(OLDN)) GO TO 80
+         IV(1) = 17
+         IF (PU .EQ. 0) GO TO 999
+C         WRITE(PU,70) VARNM(ALG1), IV(OLDN), N
+C 70      FORMAT(/5H /// ,1A1,14H CHANGED FROM ,I5,4H TO ,I5)
+         GO TO 999
+C
+ 80   IF (IV1 .LE. 11 .AND. IV1 .GE. 1) GO TO 100
+         IV(1) = 80
+C         IF (PU .NE. 0) WRITE(PU,90) IV1
+C 90      FORMAT(/13H ///  IV(1) =,I5,28H SHOULD BE BETWEEN 0 AND 14.)
+         GO TO 999
+C
+ 100  WHICH(1) = CNGD(1)
+      WHICH(2) = CNGD(2)
+      WHICH(3) = CNGD(3)
+C
+ 110  IF (IV1 .EQ. 14) IV1 = 12
+      IF (BIG .GT. TINY) GO TO 120
+         TINY = DR7MDC(1)
+         MACHEP = DR7MDC(3)
+         BIG = DR7MDC(6)
+         VM(12) = MACHEP
+         VX(12) = BIG
+         VX(13) = BIG
+         VM(14) = MACHEP
+         VM(17) = TINY
+         VX(17) = BIG
+         VM(18) = TINY
+         VX(18) = BIG
+         VX(20) = BIG
+         VX(21) = BIG
+         VX(22) = BIG
+         VM(24) = MACHEP
+         VM(25) = MACHEP
+         VM(26) = MACHEP
+         VX(28) = DR7MDC(5)
+         VM(29) = MACHEP
+         VX(30) = BIG
+         VM(33) = MACHEP
+ 120  M = 0
+      I = 1
+      J = JLIM(ALG1)
+      K = EPSLON
+      NDFALT = NDFLT(ALG1)
+      DO 150 L = 1, NDFALT
+         VK = V(K)
+         IF (VK .GE. VM(I) .AND. VK .LE. VX(I)) GO TO 140
+              M = K
+C              IF (PU .NE. 0) WRITE(PU,130) VN(1,I), VN(2,I), K, VK,
+C     1                                    VM(I), VX(I)
+C 130          FORMAT(/6H ///  ,2A4,5H.. V(,I2,3H) =,D11.3,7H SHOULD,
+C     1               11H BE BETWEEN,D11.3,4H AND,D11.3)
+ 140     K = K + 1
+         I = I + 1
+         IF (I .EQ. J) I = IJMP
+ 150     CONTINUE
+C
+      IF (IV(NVDFLT) .EQ. NDFALT) GO TO 170
+         IV(1) = 51
+         IF (PU .EQ. 0) GO TO 999
+C         WRITE(PU,160) IV(NVDFLT), NDFALT
+C 160     FORMAT(/13H IV(NVDFLT) =,I5,13H RATHER THAN ,I5)
+         GO TO 999
+ 170  IF ((IV(DTYPE) .GT. 0 .OR. V(DINIT) .GT. ZERO) .AND. IV1 .EQ. 12)
+     1                  GO TO 200
+      DO 190 I = 1, N
+         IF (D(I) .GT. ZERO) GO TO 190
+              M = 18
+C              IF (PU .NE. 0) WRITE(PU,180) I, D(I)
+C 180     FORMAT(/8H ///  D(,I3,3H) =,D11.3,19H SHOULD BE POSITIVE)
+ 190     CONTINUE
+ 200  IF (M .EQ. 0) GO TO 210
+         IV(1) = M
+         GO TO 999
+C
+ 210  IF (PU .EQ. 0 .OR. IV(PARPRT) .EQ. 0) GO TO 999
+      IF (IV1 .NE. 12 .OR. IV(INITS) .EQ. ALG1-1) GO TO 230
+         M = 1
+C         WRITE(PU,220) SH(ALG1), IV(INITS)
+C 220     FORMAT(/22H NONDEFAULT VALUES..../5H INIT,A1,14H..... IV(25) =,
+C     1          I3)
+ 230  IF (IV(DTYPE) .EQ. IV(DTYPE0)) GO TO 250
+C         IF (M .EQ. 0) WRITE(PU,260) WHICH
+         M = 1
+C         WRITE(PU,240) IV(DTYPE)
+C 240     FORMAT(20H DTYPE..... IV(16) =,I3)
+ 250  I = 1
+      J = JLIM(ALG1)
+      K = EPSLON
+      L = IV(PARSAV)
+      NDFALT = NDFLT(ALG1)
+      DO 290 II = 1, NDFALT
+         IF (V(K) .EQ. V(L)) GO TO 280
+C              IF (M .EQ. 0) WRITE(PU,260) WHICH
+C 260          FORMAT(/1H ,3A4,9HALUES..../)
+              M = 1
+C              WRITE(PU,270) VN(1,I), VN(2,I), K, V(K)
+C 270          FORMAT(1X,2A4,5H.. V(,I2,3H) =,D15.7)
+ 280     K = K + 1
+         L = L + 1
+         I = I + 1
+         IF (I .EQ. J) I = IJMP
+ 290     CONTINUE
+C
+      IV(DTYPE0) = IV(DTYPE)
+      PARSV1 = IV(PARSAV)
+      CALL DV7CPY(IV(NVDFLT), V(PARSV1), V(EPSLON))
+      GO TO 999
+C
+ 300  IV(1) = 15
+      IF (PU .EQ. 0) GO TO 999
+C      WRITE(PU,310) LIV, MIV2
+C 310  FORMAT(/10H /// LIV =,I5,17H MUST BE AT LEAST,I5)
+      IF (LIV .LT. MIV1) GO TO 999
+      IF (LV .LT. IV(LASTV)) GO TO 320
+      GO TO 999
+C
+ 320  IV(1) = 16
+C      IF (PU .NE. 0) WRITE(PU,330) LV, IV(LASTV)
+C 330  FORMAT(/9H /// LV =,I5,17H MUST BE AT LEAST,I5)
+      GO TO 999
+C
+ 340  IV(1) = 67
+C      IF (PU .NE. 0) WRITE(PU,350) ALG
+C 350  FORMAT(/10H /// ALG =,I5,21H MUST BE 1 2, 3, OR 4)
+      GO TO 999
+ 360  CONTINUE
+C 360  IF (PU .NE. 0) WRITE(PU,370) LIV, MIV1
+C 370  FORMAT(/10H /// LIV =,I5,17H MUST BE AT LEAST,I5,
+C     1       37H TO COMPUTE TRUE MIN. LIV AND MIN. LV)
+      IF (LASTIV .LE. LIV) IV(LASTIV) = MIV1
+      IF (LASTV .LE. LIV) IV(LASTV) = 0
+C
+ 999  RETURN
+C  ***  LAST LINE OF DPARCK FOLLOWS  ***
+      END
+
+      SUBROUTINE DQ7APL(NN, N, P, J, R, IERR)
+C     *****PARAMETERS.
+      INTEGER NN, N, P, IERR
+      DOUBLE PRECISION J(NN,P), R(N)
+C
+C     ..................................................................
+C     ..................................................................
+C
+C     *****PURPOSE.
+C     THIS SUBROUTINE APPLIES TO R THE ORTHOGONAL TRANSFORMATIONS
+C     STORED IN J BY QRFACT
+C
+C     *****PARAMETER DESCRIPTION.
+C     ON INPUT.
+C
+C        NN IS THE ROW DIMENSION OF THE MATRIX J AS DECLARED IN
+C             THE CALLING PROGRAM DIMENSION STATEMENT
+C
+C        N IS THE NUMBER OF ROWS OF J AND THE SIZE OF THE VECTOR R
+C
+C        P IS THE NUMBER OF COLUMNS OF J AND THE SIZE OF SIGMA
+C
+C        J CONTAINS ON AND BELOW ITS DIAGONAL THE COLUMN VECTORS
+C             U WHICH DETERMINE THE HOUSEHOLDER TRANSFORMATIONS
+C             IDENT - U*U.TRANSPOSE
+C
+C        R IS THE RIGHT HAND SIDE VECTOR TO WHICH THE ORTHOGONAL
+C             TRANSFORMATIONS WILL BE APPLIED
+C
+C        IERR IF NON-ZERO INDICATES THAT NOT ALL THE TRANSFORMATIONS
+C             WERE SUCCESSFULLY DETERMINED AND ONLY THE FIRST
+C             ABS(IERR) - 1 TRANSFORMATIONS WILL BE USED
+C
+C     ON OUTPUT.
+C
+C        R HAS BEEN OVERWRITTEN BY ITS TRANSFORMED IMAGE
+C
+C     *****APPLICATION AND USAGE RESTRICTIONS.
+C     NONE
+C
+C     *****ALGORITHM NOTES.
+C     THE VECTORS U WHICH DETERMINE THE HOUSEHOLDER TRANSFORMATIONS
+C     ARE NORMALIZED SO THAT THEIR 2-NORM SQUARED IS 2.  THE USE OF
+C     THESE TRANSFORMATIONS HERE IS IN THE SPIRIT OF (1).
+C
+C     *****SUBROUTINES AND FUNCTIONS CALLED.
+C
+C     DD7TPR - FUNCTION, RETURNS THE INNER PRODUCT OF VECTORS
+C
+C     *****REFERENCES.
+C     (1) BUSINGER, P. A., AND GOLUB, G. H. (1965), LINEAR LEAST SQUARES
+C        SOLUTIONS BY HOUSEHOLDER TRANSFORMATIONS, NUMER. MATH. 7,
+C        PP. 269-276.
+C
+C     *****HISTORY.
+C     DESIGNED BY DAVID M. GAY, CODED BY STEPHEN C. PETERS (WINTER 1977)
+C     CALL ON DV2AXY SUBSTITUTED FOR DO LOOP, FALL 1983.
+C
+C     *****GENERAL.
+C
+C     THIS SUBROUTINE WAS WRITTEN IN CONNECTION WITH RESEARCH
+C     SUPPORTED BY THE NATIONAL SCIENCE FOUNDATION UNDER GRANTS
+C     MCS-7600324, DCR75-10143, 76-14311DSS, AND MCS76-11989.
+C
+C     ..................................................................
+C     ..................................................................
+C
+C     *****LOCAL VARIABLES.
+      INTEGER K, L, NL1
+C     *****FUNCTIONS.
+      DOUBLE PRECISION DD7TPR
+      EXTERNAL DD7TPR,DV2AXY
+C
+C  ***  BODY  ***
+C
+      K = P
+      IF (IERR .NE. 0) K = IABS(IERR) - 1
+      IF ( K .EQ. 0) GO TO 999
+C
+      DO 20 L = 1, K
+         NL1 = N - L + 1
+         CALL DV2AXY(NL1, R(L), -DD7TPR(NL1,J(L,L),R(L)), J(L,L), R(L))
+ 20   CONTINUE
+C
+ 999  RETURN
+C  ***  LAST LINE OF DQ7APL FOLLOWS  ***
+      END
+
+      SUBROUTINE DV7DFL(ALG, LV, V)
+C
+C  ***  SUPPLY ***SOL (VERSION 2.3) DEFAULT VALUES TO V  ***
+C
+C  ***  ALG = 1 MEANS REGRESSION CONSTANTS.
+C  ***  ALG = 2 MEANS GENERAL UNCONSTRAINED OPTIMIZATION CONSTANTS.
+C
+      INTEGER ALG, LV
+      DOUBLE PRECISION V(LV)
+C
+      DOUBLE PRECISION DR7MDC
+      EXTERNAL DR7MDC
+C DR7MDC... RETURNS MACHINE-DEPENDENT CONSTANTS
+C
+      DOUBLE PRECISION MACHEP, MEPCRT, ONE, SQTEPS, THREE
+C
+C  ***  SUBSCRIPTS FOR V  ***
+C
+      INTEGER AFCTOL, BIAS, COSMIN, DECFAC, DELTA0, DFAC, DINIT, DLTFDC,
+     1        DLTFDJ, DTINIT, D0INIT, EPSLON, ETA0, FUZZ,
+     2        INCFAC, LMAX0, LMAXS, PHMNFC, PHMXFC, RDFCMN, RDFCMX,
+     3        RFCTOL, RLIMIT, RSPTOL, SCTOL, SIGMIN, TUNER1, TUNER2,
+     4        TUNER3, TUNER4, TUNER5, XCTOL, XFTOL
+C
+      PARAMETER (ONE=1.D+0, THREE=3.D+0)
+C
+C  ***  V SUBSCRIPT VALUES  ***
+C
+      PARAMETER (AFCTOL=31, BIAS=43, COSMIN=47, DECFAC=22, DELTA0=44,
+     1           DFAC=41, DINIT=38, DLTFDC=42, DLTFDJ=43, DTINIT=39,
+     2           D0INIT=40, EPSLON=19, ETA0=42, FUZZ=45,
+     3           INCFAC=23, LMAX0=35, LMAXS=36, PHMNFC=20, PHMXFC=21,
+     4           RDFCMN=24, RDFCMX=25, RFCTOL=32, RLIMIT=46, RSPTOL=49,
+     5           SCTOL=37, SIGMIN=50, TUNER1=26, TUNER2=27, TUNER3=28,
+     6           TUNER4=29, TUNER5=30, XCTOL=33, XFTOL=34)
+C
+C-------------------------------  BODY  --------------------------------
+C
+      MACHEP = DR7MDC(3)
+      if (MACHEP .GT. 1.D-10) then
+         V(AFCTOL) = MACHEP**2
+      else
+         V(AFCTOL) = 1.D-20
+      endif
+
+      V(DECFAC) = 0.5D+0
+      SQTEPS = DR7MDC(4)
+      V(DFAC) = 0.6D+0
+      V(DTINIT) = 1.D-6
+      MEPCRT = MACHEP ** (ONE/THREE)
+      V(D0INIT) = 1.D+0
+      V(EPSLON) = 0.1D+0
+      V(INCFAC) = 2.D+0
+      V(LMAX0) = 1.D+0
+      V(LMAXS) = 1.D+0
+      V(PHMNFC) = -0.1D+0
+      V(PHMXFC) = 0.1D+0
+      V(RDFCMN) = 0.1D+0
+      V(RDFCMX) = 4.D+0
+      V(RFCTOL) = DMAX1(1.D-10, MEPCRT**2)
+      V(SCTOL) = V(RFCTOL)
+      V(TUNER1) = 0.1D+0
+      V(TUNER2) = 1.D-4
+      V(TUNER3) = 0.75D+0
+      V(TUNER4) = 0.5D+0
+      V(TUNER5) = 0.75D+0
+      V(XCTOL) = SQTEPS
+      V(XFTOL) = 1.D+2 * MACHEP
+C
+      if (ALG .eq. 1) then
+C
+C  ***  REGRESSION  VALUES (nls)
+C
+         V(COSMIN) = DMAX1(1.D-6, 1.D+2 * MACHEP)
+         V(DINIT) = 0.D+0
+         V(DELTA0) = SQTEPS
+         V(DLTFDC) = MEPCRT
+         V(DLTFDJ) = SQTEPS
+         V(FUZZ) = 1.5D+0
+         V(RLIMIT) = DR7MDC(5)
+         V(RSPTOL) = 1.D-3
+         V(SIGMIN) = 1.D-4
+      else
+C
+C  ***  GENERAL OPTIMIZATION VALUES (nlminb)
+C
+         V(BIAS) = 0.8D+0
+         V(DINIT) = -1.0D+0
+         V(ETA0) = 1.0D+3 * MACHEP
+C
+      end if
+C  ***  LAST CARD OF DV7DFL FOLLOWS  ***
+      END
+
+      DOUBLE PRECISION FUNCTION DR7MDC(K)
+C
+C  ***  RETURN MACHINE DEPENDENT CONSTANTS USED BY NL2SOL  ***
+C
+      INTEGER K
+C
+C  ***  THE CONSTANT RETURNED DEPENDS ON K...
+C
+C  ***        K = 1... SMALLEST POS. ETA SUCH THAT -ETA EXISTS.
+C  ***        K = 2... SQUARE ROOT OF ETA.
+C  ***        K = 3... UNIT ROUNDOFF = SMALLEST POS. NO. MACHEP SUCH
+C  ***                 THAT 1 + MACHEP .GT. 1 .AND. 1 - MACHEP .LT. 1.
+C  ***        K = 4... SQUARE ROOT OF MACHEP.
+C  ***        K = 5... SQUARE ROOT OF BIG (SEE K = 6).
+C  ***        K = 6... LARGEST MACHINE NO. BIG SUCH THAT -BIG EXISTS.
+C
+      DOUBLE PRECISION BIG, ETA, MACHEP
+C/+
+      DOUBLE PRECISION DSQRT
+C/
+C
+      DOUBLE PRECISION D1MACH, ZERO
+      EXTERNAL D1MACH
+      DATA BIG/0.D+0/, ETA/0.D+0/, MACHEP/0.D+0/, ZERO/0.D+0/
+      IF (BIG .GT. ZERO) GO TO 1
+         BIG = D1MACH(2)
+         ETA = D1MACH(1)
+         MACHEP = D1MACH(4)
+ 1    CONTINUE
+C
+C-------------------------------  BODY  --------------------------------
+C
+      GO TO (10, 20, 30, 40, 50, 60), K
+C
+ 10   DR7MDC = ETA
+      GO TO 999
+C
+ 20   DR7MDC = DSQRT(256.D+0*ETA)/16.D+0
+      GO TO 999
+C
+ 30   DR7MDC = MACHEP
+      GO TO 999
+C
+ 40   DR7MDC = DSQRT(MACHEP)
+      GO TO 999
+C
+ 50   DR7MDC = DSQRT(BIG/256.D+0)*16.D+0
+      GO TO 999
+C
+ 60   DR7MDC = BIG
+C
+ 999  RETURN
+C  ***  LAST CARD OF DR7MDC FOLLOWS  ***
+      END
+      SUBROUTINE DG7ITB(B, D, G, IV, LIV, LV, P, PS, V, X, Y)
+C
+C  ***  CARRY OUT NL2SOL-LIKE ITERATIONS FOR GENERALIZED LINEAR   ***
+C  ***  REGRESSION PROBLEMS (AND OTHERS OF SIMILAR STRUCTURE)     ***
+C  ***  HAVING SIMPLE BOUNDS ON THE PARAMETERS BEING ESTIMATED.   ***
+C
+C  ***  PARAMETER DECLARATIONS  ***
+C
+      INTEGER LIV, LV, P, PS
+      INTEGER IV(LIV)
+      DOUBLE PRECISION B(2,P), D(P), G(P), V(LV), X(P), Y(P)
+C
+C--------------------------  PARAMETER USAGE  --------------------------
+C
+C B.... VECTOR OF LOWER AND UPPER BOUNDS ON X.
+C D.... SCALE VECTOR.
+C IV... INTEGER VALUE ARRAY.
+C LIV.. LENGTH OF IV.  MUST BE AT LEAST 80.
+C LH... LENGTH OF H = P*(P+1)/2.
+C LV... LENGTH OF V.  MUST BE AT LEAST P*(3*P + 19)/2 + 7.
+C G.... GRADIENT AT X (WHEN IV(1) = 2).
+C HC... GAUSS-NEWTON HESSIAN AT X (WHEN IV(1) = 2).
+C P.... NUMBER OF PARAMETERS (COMPONENTS IN X).
+C PS... NUMBER OF NONZERO ROWS AND COLUMNS IN S.
+C V.... FLOATING-POINT VALUE ARRAY.
+C X.... PARAMETER VECTOR.
+C Y.... PART OF YIELD VECTOR (WHEN IV(1)= 2, SCRATCH OTHERWISE).
+C
+C  ***  DISCUSSION  ***
+C
+C        DG7ITB IS SIMILAR TO DG7LIT, EXCEPT FOR THE EXTRA PARAMETER B
+C     -- DG7ITB ENFORCES THE BOUNDS  B(1,I) .LE. X(I) .LE. B(2,I),
+C     I = 1(1)P.
+C        DG7ITB PERFORMS NL2SOL-LIKE ITERATIONS FOR A VARIETY OF
+C     REGRESSION PROBLEMS THAT ARE SIMILAR TO NONLINEAR LEAST-SQUARES
+C     IN THAT THE HESSIAN IS THE SUM OF TWO TERMS, A READILY-COMPUTED
+C     FIRST-ORDER TERM AND A SECOND-ORDER TERM.  THE CALLER SUPPLIES
+C     THE FIRST-ORDER TERM OF THE HESSIAN IN HC (LOWER TRIANGLE, STORED
+C     COMPACTLY BY ROWS), AND DG7ITB BUILDS AN APPROXIMATION, S, TO THE
+C     SECOND-ORDER TERM.  THE CALLER ALSO PROVIDES THE FUNCTION VALUE,
+C     GRADIENT, AND PART OF THE YIELD VECTOR USED IN UPDATING S.
+C     DG7ITB DECIDES DYNAMICALLY WHETHER OR NOT TO USE S WHEN CHOOSING
+C     THE NEXT STEP TO TRY...  THE HESSIAN APPROXIMATION USED IS EITHER
+C     HC ALONE (GAUSS-NEWTON MODEL) OR HC + S (AUGMENTED MODEL).
+C     IF PS .LT. P, THEN ROWS AND COLUMNS PS+1...P OF S ARE KEPT
+C     CONSTANT.  THEY WILL BE ZERO UNLESS THE CALLER SETS IV(INITS) TO
+C     1 OR 2 AND SUPPLIES NONZERO VALUES FOR THEM, OR THE CALLER SETS
+C     IV(INITS) TO 3 OR 4 AND THE FINITE-DIFFERENCE INITIAL S THEN
+C     COMPUTED HAS NONZERO VALUES IN THESE ROWS.
+C
+C        IF IV(INITS) IS 3 OR 4, THEN THE INITIAL S IS COMPUTED BY
+C     FINITE DIFFERENCES.  3 MEANS USE FUNCTION DIFFERENCES, 4 MEANS
+C     USE GRADIENT DIFFERENCES.  FINITE DIFFERENCING IS DONE THE SAME
+C     WAY AS IN COMPUTING A COVARIANCE MATRIX (WITH IV(COVREQ) = -1, -2,
+C     1, OR 2).
+C
+C        FOR UPDATING S, DG7ITB ASSUMES THAT THE GRADIENT HAS THE FORM
+C     OF A SUM OVER I OF RHO(I,X)*GRAD(R(I,X)), WHERE GRAD DENOTES THE
+C     GRADIENT WITH RESPECT TO X.  THE TRUE SECOND-ORDER TERM THEN IS
+C     THE SUM OVER I OF RHO(I,X)*HESSIAN(R(I,X)).  IF X = X0 + STEP,
+C     THEN WE WISH TO UPDATE S SO THAT S*STEP IS THE SUM OVER I OF
+C     RHO(I,X)*(GRAD(R(I,X)) - GRAD(R(I,X0))).  THE CALLER MUST SUPPLY
+C     PART OF THIS IN Y, NAMELY THE SUM OVER I OF
+C     RHO(I,X)*GRAD(R(I,X0)), WHEN CALLING DG7ITB WITH IV(1) = 2 AND
+C     IV(MODE) = 0 (WHERE MODE = 38).  G THEN CONTANS THE OTHER PART,
+C     SO THAT THE DESIRED YIELD VECTOR IS G - Y.  IF PS .LT. P, THEN
+C     THE ABOVE DISCUSSION APPLIES ONLY TO THE FIRST PS COMPONENTS OF
+C     GRAD(R(I,X)), STEP, AND Y.
+C
+C        PARAMETERS IV, P, V, AND X ARE THE SAME AS THE CORRESPONDING
+C     ONES TO  DN2GB (AND NL2SOL), EXCEPT THAT V CAN BE SHORTER
+C     (SINCE THE PART OF V THAT  DN2GB USES FOR STORING D, J, AND R IS
+C     NOT NEEDED).  MOREOVER, COMPARED WITH  DN2GB (AND NL2SOL), IV(1)
+C     MAY HAVE THE TWO ADDITIONAL OUTPUT VALUES 1 AND 2, WHICH ARE
+C     EXPLAINED BELOW, AS IS THE USE OF IV(TOOBIG) AND IV(NFGCAL).
+C     THE VALUES IV(D), IV(J), AND IV(R), WHICH ARE OUTPUT VALUES FROM
+C      DN2GB (AND  DN2FB), ARE NOT REFERENCED BY DG7ITB OR THE
+C     SUBROUTINES IT CALLS.
+C
+C        WHEN DG7ITB IS FIRST CALLED, I.E., WHEN DG7ITB IS CALLED WITH
+C     IV(1) = 0 OR 12, V(F), G, AND HC NEED NOT BE INITIALIZED.  TO
+C     OBTAIN THESE STARTING VALUES, DG7ITB RETURNS FIRST WITH IV(1) = 1,
+C     THEN WITH IV(1) = 2, WITH IV(MODE) = -1 IN BOTH CASES.  ON
+C     SUBSEQUENT RETURNS WITH IV(1) = 2, IV(MODE) = 0 IMPLIES THAT
+C     Y MUST ALSO BE SUPPLIED.  (NOTE THAT Y IS USED FOR SCRATCH -- ITS
+C     INPUT CONTENTS ARE LOST.  BY CONTRAST, HC IS NEVER CHANGED.)
+C     ONCE CONVERGENCE HAS BEEN OBTAINED, IV(RDREQ) AND IV(COVREQ) MAY
+C     IMPLY THAT A FINITE-DIFFERENCE HESSIAN SHOULD BE COMPUTED FOR USE
+C     IN COMPUTING A COVARIANCE MATRIX.  IN THIS CASE DG7ITB WILL MAKE
+C     A NUMBER OF RETURNS WITH IV(1) = 1 OR 2 AND IV(MODE) POSITIVE.
+C     WHEN IV(MODE) IS POSITIVE, Y SHOULD NOT BE CHANGED.
+C
+C IV(1) = 1 MEANS THE CALLER SHOULD SET V(F) (I.E., V(10)) TO F(X), THE
+C             FUNCTION VALUE AT X, AND CALL DG7ITB AGAIN, HAVING CHANGED
+C             NONE OF THE OTHER PARAMETERS.  AN EXCEPTION OCCURS IF F(X)
+C             CANNOT BE EVALUATED (E.G. IF OVERFLOW WOULD OCCUR), WHICH
+C             MAY HAPPEN BECAUSE OF AN OVERSIZED STEP.  IN THIS CASE
+C             THE CALLER SHOULD SET IV(TOOBIG) = IV(2) TO 1, WHICH WILL
+C             CAUSE DG7ITB TO IGNORE V(F) AND TRY A SMALLER STEP.  NOTE
+C             THAT THE CURRENT FUNCTION EVALUATION COUNT IS AVAILABLE
+C             IN IV(NFCALL) = IV(6).  THIS MAY BE USED TO IDENTIFY
+C             WHICH COPY OF SAVED INFORMATION SHOULD BE USED IN COM-
+C             PUTING G, HC, AND Y THE NEXT TIME DG7ITB RETURNS WITH
+C             IV(1) = 2.  SEE MLPIT FOR AN EXAMPLE OF THIS.
+C IV(1) = 2 MEANS THE CALLER SHOULD SET G TO G(X), THE GRADIENT OF F AT
+C             X.  THE CALLER SHOULD ALSO SET HC TO THE GAUSS-NEWTON
+C             HESSIAN AT X.  IF IV(MODE) = 0, THEN THE CALLER SHOULD
+C             ALSO COMPUTE THE PART OF THE YIELD VECTOR DESCRIBED ABOVE.
+C             THE CALLER SHOULD THEN CALL DG7ITB AGAIN (WITH IV(1) = 2).
+C             THE CALLER MAY ALSO CHANGE D AT THIS TIME, BUT SHOULD NOT
+C             CHANGE X.  NOTE THAT IV(NFGCAL) = IV(7) CONTAINS THE
+C             VALUE THAT IV(NFCALL) HAD DURING THE RETURN WITH
+C             IV(1) = 1 IN WHICH X HAD THE SAME VALUE AS IT NOW HAS.
+C             IV(NFGCAL) IS EITHER IV(NFCALL) OR IV(NFCALL) - 1.  MLPIT
+C             IS AN EXAMPLE WHERE THIS INFORMATION IS USED.  IF G OR HC
+C             CANNOT BE EVALUATED AT X, THEN THE CALLER MAY SET
+C             IV(NFGCAL) TO 0, IN WHICH CASE DG7ITB WILL RETURN WITH
+C             IV(1) = 15.
+C
+C  ***  GENERAL  ***
+C
+C     CODED BY DAVID M. GAY.
+C
+C        (SEE NL2SOL FOR REFERENCES.)
+C
+C+++++++++++++++++++++++++++  DECLARATIONS  ++++++++++++++++++++++++++++
+C
+C  ***  LOCAL VARIABLES  ***
+C
+      LOGICAL HAVQTR, HAVRM
+      INTEGER DUMMY, DIG1, G01, H1, HC1, I, I1, IPI, IPIV0, IPIV1,
+     1        IPIV2, IPN, J, K, L, LMAT1, LSTGST, P1, P1LEN, PP1, PP1O2,
+     2        QTR1, RMAT1, RSTRST, STEP1, STPMOD, S1, TD1, TEMP1, TEMP2,
+     3        TG1, W1, WLM1, X01
+      DOUBLE PRECISION E, GI, STTSST, T, T1, XI
+C
+C     ***  CONSTANTS  ***
+C
+      DOUBLE PRECISION HALF, NEGONE, ONE, ONEP2, ZERO
+C
+C  ***  EXTERNAL FUNCTIONS AND SUBROUTINES  ***
+C
+      LOGICAL STOPX
+      DOUBLE PRECISION DD7TPR, DRLDST, DV2NRM
+      EXTERNAL DA7SST, DD7TPR, DF7DHB, DG7QSB,I7COPY, I7PNVR, I7SHFT,
+     1        DITSUM, DL7MSB, DL7SQR, DL7TVM,DL7VML,DPARCK, DQ7RSH,
+     2         DRLDST, DS7DMP, DS7IPR, DS7LUP, DS7LVM, STOPX, DV2NRM,
+     3        DV2AXY,DV7CPY, DV7IPR, DV7SCP, DV7VMP
+C
+C DA7SST.... ASSESSES CANDIDATE STEP.
+C DD7TPR... RETURNS INNER PRODUCT OF TWO VECTORS.
+C DF7DHB... COMPUTE FINITE-DIFFERENCE HESSIAN (FOR INIT. S MATRIX).
+C DG7QSB... COMPUTES GOLDFELD-QUANDT-TROTTER STEP (AUGMENTED MODEL).
+C I7COPY.... COPIES ONE INTEGER VECTOR TO ANOTHER.
+C I7PNVR... INVERTS PERMUTATION ARRAY.
+C I7SHFT... SHIFTS AN INTEGER VECTOR.
+C DITSUM.... PRINTS ITERATION SUMMARY AND INFO ON INITIAL AND FINAL X.
+C DL7MSB... COMPUTES LEVENBERG-MARQUARDT STEP (GAUSS-NEWTON MODEL).
+C DL7SQR... COMPUTES L * L**T FROM LOWER TRIANGULAR MATRIX L.
+C DL7TVM... COMPUTES L**T * V, V = VECTOR, L = LOWER TRIANGULAR MATRIX.
+C DL7VML.... COMPUTES L * V, V = VECTOR, L = LOWER TRIANGULAR MATRIX.
+C DPARCK.... CHECK VALIDITY OF IV AND V INPUT COMPONENTS.
+C DQ7RSH... SHIFTS A QR FACTORIZATION.
+C DRLDST... COMPUTES V(RELDX) = RELATIVE STEP SIZE.
+C DS7DMP... MULTIPLIES A SYM. MATRIX FORE AND AFT BY A DIAG. MATRIX.
+C DS7IPR... APPLIES PERMUTATION TO (LOWER TRIANG. OF) SYM. MATRIX.
+C DS7LUP... PERFORMS QUASI-NEWTON UPDATE ON COMPACTLY STORED LOWER TRI-
+C             ANGLE OF A SYMMETRIC MATRIX.
+C DS7LVM... MULTIPLIES COMPACTLY STORED SYM. MATRIX TIMES VECTOR.
+C STOPX.... RETURNS .TRUE. IF THE BREAK KEY HAS BEEN PRESSED.
+C DV2NRM... RETURNS THE 2-NORM OF A VECTOR.
+C DV2AXY.... COMPUTES SCALAR TIMES ONE VECTOR PLUS ANOTHER.
+C DV7CPY.... COPIES ONE VECTOR TO ANOTHER.
+C DV7IPR... APPLIES A PERMUTATION TO A VECTOR.
+C DV7SCP... SETS ALL ELEMENTS OF A VECTOR TO A SCALAR.
+C DV7VMP... MULTIPLIES (DIVIDES) VECTORS COMPONENTWISE.
+C
+C  ***  SUBSCRIPTS FOR IV AND V  ***
+C
+      INTEGER CNVCOD, COSMIN, COVMAT, COVREQ, DGNORM, DIG,
+     1        DSTNRM, F, FDH, FDIF, FUZZ, F0, GTSTEP, H, HC, IERR,
+     2        INCFAC, INITS, IPIVOT, IRC, IVNEED, KAGQT, KALM, LMAT,
+     3        LMAX0, LMAXS, MODE, MODEL, MXFCAL, MXITER, NEXTIV, NEXTV,
+     4        NFCALL, NFGCAL, NFCOV, NGCOV, NGCALL, NITER, NVSAVE, P0,
+     5        PC, PERM, PHMXFC, PREDUC, QTR, RADFAC, RADINC, RADIUS,
+     6        RAD0, RDREQ, REGD, RELDX, RESTOR, RMAT, S, SIZE, STEP,
+     7        STGLIM, STPPAR, SUSED, SWITCH, TOOBIG, TUNER4, TUNER5,
+     8        VNEED, VSAVE, W, WSCALE, XIRC, X0
+C
+C  ***  IV SUBSCRIPT VALUES  ***
+C
+C  ***  (NOTE THAT P0 AND PC ARE STORED IN IV(G0) AND IV(STLSTG) RESP.)
+C
+      PARAMETER (CNVCOD=55, COVMAT=26, COVREQ=15, DIG=37, FDH=74, H=56,
+     1           HC=71, IERR=75, INITS=25, IPIVOT=76, IRC=29, IVNEED=3,
+     2           KAGQT=33, KALM=34, LMAT=42, MODE=35, MODEL=5,
+     3           MXFCAL=17, MXITER=18, NEXTIV=46, NEXTV=47, NFCALL=6,
+     4           NFGCAL=7, NFCOV=52, NGCOV=53, NGCALL=30, NITER=31,
+     5           P0=48, PC=41, PERM=58, QTR=77, RADINC=8, RDREQ=57,
+     6           REGD=67, RESTOR=9, RMAT=78, S=62, STEP=40, STGLIM=11,
+     7           SUSED=64, SWITCH=12, TOOBIG=2, VNEED=4, VSAVE=60, W=65,
+     8           XIRC=13, X0=43)
+C
+C  ***  V SUBSCRIPT VALUES  ***
+C
+      PARAMETER (COSMIN=47, DGNORM=1, DSTNRM=2, F=10, FDIF=11, FUZZ=45,
+     1           F0=13, GTSTEP=4, INCFAC=23, LMAX0=35, LMAXS=36,
+     2           NVSAVE=9, PHMXFC=21, PREDUC=7, RADFAC=16, RADIUS=8,
+     3           RAD0=9, RELDX=17, SIZE=55, STPPAR=5, TUNER4=29,
+     4           TUNER5=30, WSCALE=56)
+C
+C
+      PARAMETER (HALF=0.5D+0, NEGONE=-1.D+0, ONE=1.D+0, ONEP2=1.2D+0,
+     1           ZERO=0.D+0)
+C
+C+++++++++++++++++++++++++++++++  BODY  ++++++++++++++++++++++++++++++++
+C
+      I = IV(1)
+      IF (I .EQ. 1) GO TO 50
+      IF (I .EQ. 2) GO TO 60
+C
+      IF (I .LT. 12) GO TO 10
+      IF (I .GT. 13) GO TO 10
+         IV(VNEED) = IV(VNEED) + P*(3*P + 25)/2 + 7
+         IV(IVNEED) = IV(IVNEED) + 4*P
+ 10   CALL DPARCK(1, D, IV, LIV, LV, P, V)
+      I = IV(1) - 2
+      IF (I .GT. 12) GO TO 999
+      GO TO (360, 360, 360, 360, 360, 360, 240, 190, 240, 20, 20, 30), I
+C
+C  ***  STORAGE ALLOCATION  ***
+C
+ 20   PP1O2 = P * (P + 1) / 2
+      IV(S) = IV(LMAT) + PP1O2
+      IV(X0) = IV(S) + PP1O2
+      IV(STEP) = IV(X0) + 2*P
+      IV(DIG) = IV(STEP) + 3*P
+      IV(W) = IV(DIG) + 2*P
+      IV(H) = IV(W) + 4*P + 7
+      IV(NEXTV) = IV(H) + PP1O2
+      IV(IPIVOT) = IV(PERM) + 3*P
+      IV(NEXTIV) = IV(IPIVOT) + P
+      IF (IV(1) .NE. 13) GO TO 30
+         IV(1) = 14
+         GO TO 999
+C
+C  ***  INITIALIZATION  ***
+C
+ 30   IV(NITER) = 0
+      IV(NFCALL) = 1
+      IV(NGCALL) = 1
+      IV(NFGCAL) = 1
+      IV(MODE) = -1
+      IV(STGLIM) = 2
+      IV(TOOBIG) = 0
+      IV(CNVCOD) = 0
+      IV(COVMAT) = 0
+      IV(NFCOV) = 0
+      IV(NGCOV) = 0
+      IV(RADINC) = 0
+      IV(PC) = P
+      V(RAD0) = ZERO
+      V(STPPAR) = ZERO
+      V(RADIUS) = V(LMAX0) / (ONE + V(PHMXFC))
+C
+C  ***  CHECK CONSISTENCY OF B AND INITIALIZE IP ARRAY  ***
+C
+      IPI = IV(IPIVOT)
+      DO 40 I = 1, P
+         IV(IPI) = I
+         IPI = IPI + 1
+         IF (B(1,I) .GT. B(2,I)) GO TO 680
+ 40      CONTINUE
+C
+C  ***  SET INITIAL MODEL AND S MATRIX  ***
+C
+      IV(MODEL) = 1
+      IV(1) = 1
+      IF (IV(S) .LT. 0) GO TO 710
+      IF (IV(INITS) .GT. 1) IV(MODEL) = 2
+      S1 = IV(S)
+      IF (IV(INITS) .EQ. 0 .OR. IV(INITS) .GT. 2)
+     1   CALL DV7SCP(P*(P+1)/2, V(S1), ZERO)
+      GO TO 710
+C
+C  ***  NEW FUNCTION VALUE  ***
+C
+ 50   IF (IV(MODE) .EQ. 0) GO TO 360
+      IF (IV(MODE) .GT. 0) GO TO 590
+C
+      IF (IV(TOOBIG) .EQ. 0) GO TO 690
+         IV(1) = 63
+         GO TO 999
+C
+C  ***  MAKE SURE GRADIENT COULD BE COMPUTED  ***
+C
+ 60   IF (IV(TOOBIG) .EQ. 0) GO TO 70
+         IV(1) = 65
+         GO TO 999
+C
+C  ***  NEW GRADIENT  ***
+C
+ 70   IV(KALM) = -1
+      IV(KAGQT) = -1
+      IV(FDH) = 0
+      IF (IV(MODE) .GT. 0) GO TO 590
+      IF (IV(HC) .LE. 0 .AND. IV(RMAT) .LE. 0) GO TO 670
+C
+C  ***  CHOOSE INITIAL PERMUTATION  ***
+C
+      IPI = IV(IPIVOT)
+      IPN = IPI + P - 1
+      IPIV2 = IV(PERM) - 1
+      K = IV(PC)
+      P1 = P
+      PP1 = P + 1
+      RMAT1 = IV(RMAT)
+      HAVRM = RMAT1 .GT. 0
+      QTR1 = IV(QTR)
+      HAVQTR = QTR1 .GT. 0
+C     *** MAKE SURE V(QTR1) IS LEGAL (EVEN WHEN NOT REFERENCED) ***
+      W1 = IV(W)
+      IF (.NOT. HAVQTR) QTR1 = W1 + P
+C
+      DO 100 I = 1, P
+         I1 = IV(IPN)
+         IPN = IPN - 1
+         IF (B(1,I1) .GE. B(2,I1)) GO TO 80
+         XI = X(I1)
+         GI = G(I1)
+         IF (XI .LE. B(1,I1) .AND. GI .GT. ZERO) GO TO 80
+         IF (XI .GE. B(2,I1) .AND. GI .LT. ZERO) GO TO 80
+C           *** DISALLOW CONVERGENCE IF X(I1) HAS JUST BEEN FREED ***
+            J = IPIV2 + I1
+            IF (IV(J) .GT. K) IV(CNVCOD) = 0
+            GO TO 100
+ 80      IF (I1 .GE. P1) GO TO 90
+            I1 = PP1 - I
+            CALL I7SHFT(P1, I1, IV(IPI))
+            IF (HAVRM)
+     1          CALL DQ7RSH(I1, P1, HAVQTR, V(QTR1), V(RMAT1), V(W1))
+ 90      P1 = P1 - 1
+ 100     CONTINUE
+      IV(PC) = P1
+C
+C  ***  COMPUTE V(DGNORM) (AN OUTPUT VALUE IF WE STOP NOW)  ***
+C
+      V(DGNORM) = ZERO
+      IF (P1 .LE. 0) GO TO 110
+      DIG1 = IV(DIG)
+      CALL DV7VMP(P, V(DIG1), G, D, -1)
+      CALL DV7IPR(P, IV(IPI), V(DIG1))
+      V(DGNORM) = DV2NRM(P1, V(DIG1))
+ 110  IF (IV(CNVCOD) .NE. 0) GO TO 580
+      IF (IV(MODE) .EQ. 0) GO TO 510
+      IV(MODE) = 0
+      V(F0) = V(F)
+      IF (IV(INITS) .LE. 2) GO TO 170
+C
+C  ***  ARRANGE FOR FINITE-DIFFERENCE INITIAL S  ***
+C
+      IV(XIRC) = IV(COVREQ)
+      IV(COVREQ) = -1
+      IF (IV(INITS) .GT. 3) IV(COVREQ) = 1
+      IV(CNVCOD) = 70
+      GO TO 600
+C
+C  ***  COME TO NEXT STMT AFTER COMPUTING F.D. HESSIAN FOR INIT. S  ***
+C
+ 120  H1 = IV(FDH)
+      IF (H1 .LE. 0) GO TO 660
+      IV(CNVCOD) = 0
+      IV(MODE) = 0
+      IV(NFCOV) = 0
+      IV(NGCOV) = 0
+      IV(COVREQ) = IV(XIRC)
+      S1 = IV(S)
+      PP1O2 = PS * (PS + 1) / 2
+      HC1 = IV(HC)
+      IF (HC1 .LE. 0) GO TO 130
+         CALL DV2AXY(PP1O2, V(S1), NEGONE, V(HC1), V(H1))
+         GO TO 140
+ 130  RMAT1 = IV(RMAT)
+      LMAT1 = IV(LMAT)
+      CALL DL7SQR(P, V(LMAT1), V(RMAT1))
+      IPI = IV(IPIVOT)
+      IPIV1 = IV(PERM) + P
+      CALL I7PNVR(P, IV(IPIV1), IV(IPI))
+      CALL DS7IPR(P, IV(IPIV1), V(LMAT1))
+      CALL DV2AXY(PP1O2, V(S1), NEGONE, V(LMAT1), V(H1))
+C
+C     *** ZERO PORTION OF S CORRESPONDING TO FIXED X COMPONENTS ***
+C
+ 140  DO 160 I = 1, P
+         IF (B(1,I) .LT. B(2,I)) GO TO 160
+         K = S1 + I*(I-1)/2
+         CALL DV7SCP(I, V(K), ZERO)
+         IF (I .GE. P) GO TO 170
+         K = K + 2*I - 1
+         I1 = I + 1
+         DO 150 J = I1, P
+            V(K) = ZERO
+            K = K + J
+ 150        CONTINUE
+ 160     CONTINUE
+C
+ 170  IV(1) = 2
+C
+C
+C-----------------------------  MAIN LOOP  -----------------------------
+C
+C
+C  ***  PRINT ITERATION SUMMARY, CHECK ITERATION LIMIT  ***
+C
+ 180  CALL DITSUM(D, G, IV, LIV, LV, P, V, X)
+ 190  K = IV(NITER)
+      IF (K .LT. IV(MXITER)) GO TO 200
+         IV(1) = 10
+         GO TO 999
+ 200  IV(NITER) = K + 1
+C
+C  ***  UPDATE RADIUS  ***
+C
+      IF (K .EQ. 0) GO TO 220
+      STEP1 = IV(STEP)
+      DO 210 I = 1, P
+         V(STEP1) = D(I) * V(STEP1)
+         STEP1 = STEP1 + 1
+ 210     CONTINUE
+      STEP1 = IV(STEP)
+      T = V(RADFAC) * DV2NRM(P, V(STEP1))
+      IF (V(RADFAC) .LT. ONE .OR. T .GT. V(RADIUS)) V(RADIUS) = T
+C
+C  ***  INITIALIZE FOR START OF NEXT ITERATION  ***
+C
+ 220  X01 = IV(X0)
+      V(F0) = V(F)
+      IV(IRC) = 4
+      IV(H) = -IABS(IV(H))
+      IV(SUSED) = IV(MODEL)
+C
+C     ***  COPY X TO X0  ***
+C
+      CALL DV7CPY(P, V(X01), X)
+C
+C  ***  CHECK STOPX AND FUNCTION EVALUATION LIMIT  ***
+C
+ 230  IF (.NOT. STOPX(DUMMY)) GO TO 250
+         IV(1) = 11
+         GO TO 260
+C
+C     ***  COME HERE WHEN RESTARTING AFTER FUNC. EVAL. LIMIT OR STOPX.
+C
+ 240  IF (V(F) .GE. V(F0)) GO TO 250
+         V(RADFAC) = ONE
+         K = IV(NITER)
+         GO TO 200
+C
+ 250  IF (IV(NFCALL) .LT. IV(MXFCAL) + IV(NFCOV)) GO TO 270
+         IV(1) = 9
+ 260     IF (V(F) .GE. V(F0)) GO TO 999
+C
+C        ***  IN CASE OF STOPX OR FUNCTION EVALUATION LIMIT WITH
+C        ***  IMPROVED V(F), EVALUATE THE GRADIENT AT X.
+C
+              IV(CNVCOD) = IV(1)
+              GO TO 500
+C
+C. . . . . . . . . . . . .  COMPUTE CANDIDATE STEP  . . . . . . . . . .
+C
+ 270  STEP1 = IV(STEP)
+      TG1 = IV(DIG)
+      TD1 = TG1 + P
+      X01 = IV(X0)
+      W1 = IV(W)
+      H1 = IV(H)
+      P1 = IV(PC)
+      IPI = IV(PERM)
+      IPIV1 = IPI + P
+      IPIV2 = IPIV1 + P
+      IPIV0 = IV(IPIVOT)
+      IF (IV(MODEL) .EQ. 2) GO TO 280
+C
+C        ***  COMPUTE LEVENBERG-MARQUARDT STEP IF POSSIBLE...
+C
+         RMAT1 = IV(RMAT)
+         IF (RMAT1 .LE. 0) GO TO 280
+         QTR1 = IV(QTR)
+         IF (QTR1 .LE. 0) GO TO 280
+         LMAT1 = IV(LMAT)
+         WLM1 = W1 + P
+         CALL DL7MSB(B, D, G, IV(IERR), IV(IPIV0), IV(IPIV1),
+     1               IV(IPIV2), IV(KALM), V(LMAT1), LV, P, IV(P0),
+     2               IV(PC), V(QTR1), V(RMAT1), V(STEP1), V(TD1),
+     3               V(TG1), V, V(W1), V(WLM1), X, V(X01))
+C        *** H IS STORED IN THE END OF W AND HAS JUST BEEN OVERWRITTEN,
+C        *** SO WE MARK IT INVALID...
+         IV(H) = -IABS(H1)
+C        *** EVEN IF H WERE STORED ELSEWHERE, IT WOULD BE NECESSARY TO
+C        *** MARK INVALID THE INFORMATION DG7QTS MAY HAVE STORED IN V...
+         IV(KAGQT) = -1
+         GO TO 330
+C
+ 280  IF (H1 .GT. 0) GO TO 320
+C
+C     ***  SET H TO  D**-1 * (HC + T1*S) * D**-1.  ***
+C
+         P1LEN = P1*(P1+1)/2
+         H1 = -H1
+         IV(H) = H1
+         IV(FDH) = 0
+         IF (P1 .LE. 0) GO TO 320
+C        *** MAKE TEMPORARY PERMUTATION ARRAY ***
+         CALL I7COPY(P, IV(IPI), IV(IPIV0))
+         J = IV(HC)
+         IF (J .GT. 0) GO TO 290
+            J = H1
+            RMAT1 = IV(RMAT)
+            CALL DL7SQR(P1, V(H1), V(RMAT1))
+            GO TO 300
+ 290     CALL DV7CPY(P*(P+1)/2, V(H1), V(J))
+         CALL DS7IPR(P, IV(IPI), V(H1))
+ 300     IF (IV(MODEL) .EQ. 1) GO TO 310
+            LMAT1 = IV(LMAT)
+            S1 = IV(S)
+            CALL DV7CPY(P*(P+1)/2, V(LMAT1), V(S1))
+            CALL DS7IPR(P, IV(IPI), V(LMAT1))
+            CALL DV2AXY(P1LEN, V(H1), ONE, V(LMAT1), V(H1))
+ 310     CALL DV7CPY(P, V(TD1), D)
+         CALL DV7IPR(P, IV(IPI), V(TD1))
+         CALL DS7DMP(P1, V(H1), V(H1), V(TD1), -1)
+         IV(KAGQT) = -1
+C
+C  ***  COMPUTE ACTUAL GOLDFELD-QUANDT-TROTTER STEP  ***
+C
+ 320  LMAT1 = IV(LMAT)
+      CALL DG7QSB(B, D, V(H1), G, IV(IPI), IV(IPIV1), IV(IPIV2),
+     1            IV(KAGQT), V(LMAT1), LV, P, IV(P0), P1, V(STEP1),
+     2            V(TD1), V(TG1), V, V(W1), X, V(X01))
+      IF (IV(KALM) .GT. 0) IV(KALM) = 0
+C
+ 330  IF (IV(IRC) .NE. 6) GO TO 340
+         IF (IV(RESTOR) .NE. 2) GO TO 360
+         RSTRST = 2
+         GO TO 370
+C
+C  ***  CHECK WHETHER EVALUATING F(X0 + STEP) LOOKS WORTHWHILE  ***
+C
+ 340  IV(TOOBIG) = 0
+      IF (V(DSTNRM) .LE. ZERO) GO TO 360
+      IF (IV(IRC) .NE. 5) GO TO 350
+      IF (V(RADFAC) .LE. ONE) GO TO 350
+      IF (V(PREDUC) .GT. ONEP2 * V(FDIF)) GO TO 350
+         STEP1 = IV(STEP)
+         X01 = IV(X0)
+         CALL DV2AXY(P, V(STEP1), NEGONE, V(X01), X)
+         IF (IV(RESTOR) .NE. 2) GO TO 360
+         RSTRST = 0
+         GO TO 370
+C
+C  ***  COMPUTE F(X0 + STEP)  ***
+C
+ 350  X01 = IV(X0)
+      STEP1 = IV(STEP)
+      CALL DV2AXY(P, X, ONE, V(STEP1), V(X01))
+      IV(NFCALL) = IV(NFCALL) + 1
+      IV(1) = 1
+      GO TO 710
+C
+C. . . . . . . . . . . . .  ASSESS CANDIDATE STEP  . . . . . . . . . . .
+C
+ 360  RSTRST = 3
+ 370  X01 = IV(X0)
+      V(RELDX) = DRLDST(P, D, X, V(X01))
+      CALL DA7SST(IV, LIV, LV, V)
+      STEP1 = IV(STEP)
+      LSTGST = X01 + P
+      I = IV(RESTOR) + 1
+      GO TO (410, 380, 390, 400), I
+ 380  CALL DV7CPY(P, X, V(X01))
+      GO TO 410
+ 390   CALL DV7CPY(P, V(LSTGST), V(STEP1))
+       GO TO 410
+ 400     CALL DV7CPY(P, V(STEP1), V(LSTGST))
+         CALL DV2AXY(P, X, ONE, V(STEP1), V(X01))
+         V(RELDX) = DRLDST(P, D, X, V(X01))
+         IV(RESTOR) = RSTRST
+C
+C  ***  IF NECESSARY, SWITCH MODELS  ***
+C
+ 410  IF (IV(SWITCH) .EQ. 0) GO TO 420
+         IV(H) = -IABS(IV(H))
+         IV(SUSED) = IV(SUSED) + 2
+         L = IV(VSAVE)
+         CALL DV7CPY(NVSAVE, V, V(L))
+ 420  L = IV(IRC) - 4
+      STPMOD = IV(MODEL)
+      IF (L .GT. 0) GO TO (440,450,460,460,460,460,460,460,570,510), L
+C
+C  ***  DECIDE WHETHER TO CHANGE MODELS  ***
+C
+      E = V(PREDUC) - V(FDIF)
+      S1 = IV(S)
+      CALL DS7LVM(PS, Y, V(S1), V(STEP1))
+      STTSST = HALF * DD7TPR(PS, V(STEP1), Y)
+      IF (IV(MODEL) .EQ. 1) STTSST = -STTSST
+      IF (DABS(E + STTSST) * V(FUZZ) .GE. DABS(E)) GO TO 430
+C
+C     ***  SWITCH MODELS  ***
+C
+         IV(MODEL) = 3 - IV(MODEL)
+         IF (-2 .LT. L) GO TO 470
+              IV(H) = -IABS(IV(H))
+              IV(SUSED) = IV(SUSED) + 2
+              L = IV(VSAVE)
+              CALL DV7CPY(NVSAVE, V(L), V)
+              GO TO 230
+C
+ 430  IF (-3 .LT. L) GO TO 470
+C
+C     ***  RECOMPUTE STEP WITH DIFFERENT RADIUS  ***
+C
+ 440  V(RADIUS) = V(RADFAC) * V(DSTNRM)
+      GO TO 230
+C
+C  ***  COMPUTE STEP OF LENGTH V(LMAXS) FOR SINGULAR CONVERGENCE TEST
+C
+ 450  V(RADIUS) = V(LMAXS)
+      GO TO 270
+C
+C  ***  CONVERGENCE OR FALSE CONVERGENCE  ***
+C
+ 460  IV(CNVCOD) = L
+      IF (V(F) .GE. V(F0)) GO TO 580
+         IF (IV(XIRC) .EQ. 14) GO TO 580
+              IV(XIRC) = 14
+C
+C. . . . . . . . . . . .  PROCESS ACCEPTABLE STEP  . . . . . . . . . . .
+C
+ 470  IV(COVMAT) = 0
+      IV(REGD) = 0
+C
+C  ***  SEE WHETHER TO SET V(RADFAC) BY GRADIENT TESTS  ***
+C
+      IF (IV(IRC) .NE. 3) GO TO 500
+         STEP1 = IV(STEP)
+         TEMP1 = STEP1 + P
+         TEMP2 = IV(X0)
+C
+C     ***  SET  TEMP1 = HESSIAN * STEP  FOR USE IN GRADIENT TESTS  ***
+C
+         HC1 = IV(HC)
+         IF (HC1 .LE. 0) GO TO 480
+              CALL DS7LVM(P, V(TEMP1), V(HC1), V(STEP1))
+              GO TO 490
+ 480     RMAT1 = IV(RMAT)
+         IPIV0 = IV(IPIVOT)
+         CALL DV7CPY(P, V(TEMP1), V(STEP1))
+         CALL DV7IPR(P, IV(IPIV0), V(TEMP1))
+         CALL DL7TVM(P, V(TEMP1), V(RMAT1), V(TEMP1))
+         CALL DL7VML(P, V(TEMP1), V(RMAT1), V(TEMP1))
+         IPIV1 = IV(PERM) + P
+         CALL I7PNVR(P, IV(IPIV1), IV(IPIV0))
+         CALL DV7IPR(P, IV(IPIV1), V(TEMP1))
+C
+ 490     IF (STPMOD .EQ. 1) GO TO 500
+              S1 = IV(S)
+              CALL DS7LVM(PS, V(TEMP2), V(S1), V(STEP1))
+              CALL DV2AXY(PS, V(TEMP1), ONE, V(TEMP2), V(TEMP1))
+C
+C  ***  SAVE OLD GRADIENT AND COMPUTE NEW ONE  ***
+C
+ 500  IV(NGCALL) = IV(NGCALL) + 1
+      G01 = IV(W)
+      CALL DV7CPY(P, V(G01), G)
+      GO TO 690
+C
+C  ***  INITIALIZATIONS -- G0 = G - G0, ETC.  ***
+C
+ 510  G01 = IV(W)
+      CALL DV2AXY(P, V(G01), NEGONE, V(G01), G)
+      STEP1 = IV(STEP)
+      TEMP1 = STEP1 + P
+      TEMP2 = IV(X0)
+      IF (IV(IRC) .NE. 3) GO TO 540
+C
+C  ***  SET V(RADFAC) BY GRADIENT TESTS  ***
+C
+C     ***  SET  TEMP1 = D**-1 * (HESSIAN * STEP  +  (G(X0) - G(X)))  ***
+C
+         K = TEMP1
+         L = G01
+         DO 520 I = 1, P
+              V(K) = (V(K) - V(L)) / D(I)
+              K = K + 1
+              L = L + 1
+ 520          CONTINUE
+C
+C        ***  DO GRADIENT TESTS  ***
+C
+         IF (DV2NRM(P, V(TEMP1)) .LE. V(DGNORM) * V(TUNER4))  GO TO 530
+              IF (DD7TPR(P, G, V(STEP1))
+     1                  .GE. V(GTSTEP) * V(TUNER5))  GO TO 540
+ 530               V(RADFAC) = V(INCFAC)
+C
+C  ***  COMPUTE Y VECTOR NEEDED FOR UPDATING S  ***
+C
+ 540  CALL DV2AXY(PS, Y, NEGONE, Y, G)
+C
+C  ***  DETERMINE SIZING FACTOR V(SIZE)  ***
+C
+C     ***  SET TEMP1 = S * STEP  ***
+      S1 = IV(S)
+      CALL DS7LVM(PS, V(TEMP1), V(S1), V(STEP1))
+C
+      T1 = DABS(DD7TPR(PS, V(STEP1), V(TEMP1)))
+      T = DABS(DD7TPR(PS, V(STEP1), Y))
+      V(SIZE) = ONE
+      IF (T .LT. T1) V(SIZE) = T / T1
+C
+C  ***  SET G0 TO WCHMTD CHOICE OF FLETCHER AND AL-BAALI  ***
+C
+      HC1 = IV(HC)
+      IF (HC1 .LE. 0) GO TO 550
+         CALL DS7LVM(PS, V(G01), V(HC1), V(STEP1))
+         GO TO 560
+C
+ 550  RMAT1 = IV(RMAT)
+      IPIV0 = IV(IPIVOT)
+      CALL DV7CPY(P, V(G01), V(STEP1))
+      I = G01 + PS
+      IF (PS .LT. P) CALL DV7SCP(P-PS, V(I), ZERO)
+      CALL DV7IPR(P, IV(IPIV0), V(G01))
+      CALL DL7TVM(P, V(G01), V(RMAT1), V(G01))
+      CALL DL7VML(P, V(G01), V(RMAT1), V(G01))
+      IPIV1 = IV(PERM) + P
+      CALL I7PNVR(P, IV(IPIV1), IV(IPIV0))
+      CALL DV7IPR(P, IV(IPIV1), V(G01))
+C
+ 560  CALL DV2AXY(PS, V(G01), ONE, Y, V(G01))
+C
+C  ***  UPDATE S  ***
+C
+      CALL DS7LUP(V(S1), V(COSMIN), PS, V(SIZE), V(STEP1), V(TEMP1),
+     1            V(TEMP2), V(G01), V(WSCALE), Y)
+      IV(1) = 2
+      GO TO 180
+C
+C. . . . . . . . . . . . . .  MISC. DETAILS  . . . . . . . . . . . . . .
+C
+C  ***  BAD PARAMETERS TO ASSESS  ***
+C
+ 570  IV(1) = 64
+      GO TO 999
+C
+C
+C  ***  CONVERGENCE OBTAINED -- SEE WHETHER TO COMPUTE COVARIANCE  ***
+C
+ 580  IF (IV(RDREQ) .EQ. 0) GO TO 660
+      IF (IV(FDH) .NE. 0) GO TO 660
+      IF (IV(CNVCOD) .GE. 7) GO TO 660
+      IF (IV(REGD) .GT. 0) GO TO 660
+      IF (IV(COVMAT) .GT. 0) GO TO 660
+      IF (IABS(IV(COVREQ)) .GE. 3) GO TO 640
+      IF (IV(RESTOR) .EQ. 0) IV(RESTOR) = 2
+      GO TO 600
+C
+C  ***  COMPUTE FINITE-DIFFERENCE HESSIAN FOR COMPUTING COVARIANCE  ***
+C
+ 590  IV(RESTOR) = 0
+ 600  CALL DF7DHB(B, D, G, I, IV, LIV, LV, P, V, X)
+      GO TO (610, 620, 630), I
+ 610  IV(NFCOV) = IV(NFCOV) + 1
+      IV(NFCALL) = IV(NFCALL) + 1
+      IV(1) = 1
+      GO TO 710
+C
+ 620  IV(NGCOV) = IV(NGCOV) + 1
+      IV(NGCALL) = IV(NGCALL) + 1
+      IV(NFGCAL) = IV(NFCALL) + IV(NGCOV)
+      GO TO 690
+C
+ 630  IF (IV(CNVCOD) .EQ. 70) GO TO 120
+      GO TO 660
+C
+ 640  H1 = IABS(IV(H))
+      IV(FDH) = H1
+      IV(H) = -H1
+      HC1 = IV(HC)
+      IF (HC1 .LE. 0) GO TO 650
+           CALL DV7CPY(P*(P+1)/2, V(H1), V(HC1))
+           GO TO 660
+ 650  RMAT1 = IV(RMAT)
+      CALL DL7SQR(P, V(H1), V(RMAT1))
+C
+ 660  IV(MODE) = 0
+      IV(1) = IV(CNVCOD)
+      IV(CNVCOD) = 0
+      GO TO 999
+C
+C  ***  SPECIAL RETURN FOR MISSING HESSIAN INFORMATION -- BOTH
+C  ***  IV(HC) .LE. 0 AND IV(RMAT) .LE. 0
+C
+ 670  IV(1) = 1400
+      GO TO 999
+C
+C  ***  INCONSISTENT B  ***
+C
+ 680  IV(1) = 82
+      GO TO 999
+C
+C  *** SAVE, THEN INITIALIZE IPIVOT ARRAY BEFORE COMPUTING G ***
+C
+ 690  IV(1) = 2
+      J = IV(IPIVOT)
+      IPI = IV(PERM)
+      CALL I7PNVR(P, IV(IPI), IV(J))
+      DO 700 I = 1, P
+         IV(J) = I
+         J = J + 1
+ 700     CONTINUE
+C
+C  ***  PROJECT X INTO FEASIBLE REGION (PRIOR TO COMPUTING F OR G)  ***
+C
+ 710  DO 720 I = 1, P
+         IF (X(I) .LT. B(1,I)) X(I) = B(1,I)
+         IF (X(I) .GT. B(2,I)) X(I) = B(2,I)
+ 720     CONTINUE
+      IV(TOOBIG) = 0
+C
+ 999  RETURN
+C
+C  ***  LAST LINE OF DG7ITB FOLLOWS  ***
+      END
+      SUBROUTINE DRNSGB(A, ALF, B, C, DA, IN, IV, L, L1, LA, LIV, LV,
+     1                  N, NDA, P, V, Y)
+C
+C  ***  ITERATION DRIVER FOR SEPARABLE NONLINEAR LEAST SQUARES,
+C  ***  WITH SIMPLE BOUNDS ON THE NONLINEAR VARIABLES.
+C
+C  ***  PARAMETER DECLARATIONS  ***
+C
+      INTEGER L, L1, LA, LIV, LV, N, NDA, P
+      INTEGER IN(2,NDA), IV(LIV)
+C     DIMENSION UIPARM(*)
+      DOUBLE PRECISION A(LA,L1), ALF(P), B(2,P), C(L), DA(LA,NDA),
+     1                 V(LV), Y(N)
+C
+C  ***  PURPOSE  ***
+C
+C GIVEN A SET OF N OBSERVATIONS Y(1)....Y(N) OF A DEPENDENT VARIABLE
+C T(1)...T(N), DRNSGB ATTEMPTS TO COMPUTE A LEAST SQUARES FIT
+C TO A FUNCTION  ETA  (THE MODEL) WHICH IS A LINEAR COMBINATION
+C
+C                  L
+C ETA(C,ALF,T) =  SUM C * PHI(ALF,T) +PHI   (ALF,T)
+C                 J=1  J     J           L+1
+C
+C OF NONLINEAR FUNCTIONS PHI(J) DEPENDENT ON T AND ALF(1),...,ALF(P)
+C (.E.G. A SUM OF EXPONENTIALS OR GAUSSIANS).  THAT IS, IT DETERMINES
+C NONLINEAR PARAMETERS ALF WHICH MINIMIZE
+C
+C                   2    N                      2
+C     NORM(RESIDUAL)  = SUM  (Y - ETA(C,ALF,T )) ,
+C                       I=1    I             I
+C
+C SUBJECT TO THE SIMPLE BOUND CONSTRAINTS
+C B(1,I) .LE. ALF(I) .LE. B(2,I), I = 1(1)P.
+C
+C THE (L+1)ST TERM IS OPTIONAL.
+C
+C
+C  ***  PARAMETERS  ***
+C
+C      A (IN)  MATRIX PHI(ALF,T) OF THE MODEL.
+C    ALF (I/O) NONLINEAR PARAMETERS.
+C                 INPUT = INITIAL GUESS,
+C                 OUTPUT = BEST ESTIMATE FOUND.
+C      C (OUT) LINEAR PARAMETERS (ESTIMATED).
+C     DA (IN)  DERIVATIVES OF COLUMNS OF A WITH RESPECT TO COMPONENTS
+C                 OF ALF, AS SPECIFIED BY THE IN ARRAY...
+C     IN (IN)  WHEN DRNSGB IS CALLED WITH IV(1) = 2 OR -2, THEN FOR
+C                 I = 1(1)NDA, COLUMN I OF DA IS THE PARTIAL
+C                 DERIVATIVE WITH RESPECT TO ALF(IN(1,I)) OF COLUMN
+C                 IN(2,I) OF A, UNLESS IV(1,I) IS NOT POSITIVE (IN
+C                 WHICH CASE COLUMN I OF DA IS IGNORED.  IV(1) = -2
+C                 MEANS THERE ARE MORE COLUMNS OF DA TO COME AND
+C                 DRNSGB SHOULD RETURN FOR THEM.
+C     IV (I/O) INTEGER PARAMETER AND SCRATCH VECTOR.  DRNSGB RETURNS
+C                 WITH IV(1) = 1 WHEN IT WANTS A TO BE EVALUATED AT
+C                 ALF AND WITH IV(1) = 2 WHEN IT WANTS DA TO BE
+C                 EVALUATED AT ALF.  WHEN CALLED WITH IV(1) = -2
+C                 (AFTER A RETURN WITH IV(1) = 2), DRNSGB RETURNS
+C                 WITH IV(1) = -2 TO GET MORE COLUMNS OF DA.
+C      L (IN)  NUMBER OF LINEAR PARAMETERS TO BE ESTIMATED.
+C     L1 (IN)  L+1 IF PHI(L+1) IS IN THE MODEL, L IF NOT.
+C     LA (IN)  LEAD DIMENSION OF A.  MUST BE AT LEAST N.
+C    LIV (IN)  LENGTH OF IV.  MUST BE AT LEAST 110 + L + 4*P.
+C     LV (IN)  LENGTH OF V.  MUST BE AT LEAST
+C                 105 + 2*N + L*(L+3)/2 + P*(2*P + 21 + N).
+C      N (IN)  NUMBER OF OBSERVATIONS.
+C    NDA (IN)  NUMBER OF COLUMNS IN DA AND IN.
+C      P (IN)  NUMBER OF NONLINEAR PARAMETERS TO BE ESTIMATED.
+C      V (I/O) FLOATING-POINT PARAMETER AND SCRATCH VECTOR.
+C      Y (IN)  RIGHT-HAND SIDE VECTOR.
+C
+C
+C  ***  EXTERNAL SUBROUTINES  ***
+C
+      DOUBLE PRECISION DL7SVX, DL7SVN, DR7MDC
+      EXTERNAL DIVSET,DITSUM, DL7ITV, DL7SVX, DL7SVN, DRN2GB, DQ7APL,
+     1        DQ7RFH, DR7MDC, DS7CPR,DV2AXY,DV7CPY,DV7PRM, DV7SCP
+C
+C DIVSET.... SUPPLIES DEFAULT PARAMETER VALUES.
+C DITSUM.... PRINTS ITERATION SUMMARY, INITIAL AND FINAL ALF.
+C DL7ITV... APPLIES INVERSE-TRANSPOSE OF COMPACT LOWER TRIANG. MATRIX.
+C DL7SVX... ESTIMATES LARGEST SING. VALUE OF LOWER TRIANG. MATRIX.
+C DL7SVN... ESTIMATES SMALLEST SING. VALUE OF LOWER TRIANG. MATRIX.
+C DRN2GB... UNDERLYING NONLINEAR LEAST-SQUARES SOLVER.
+C DQ7APL... APPLIES HOUSEHOLDER TRANSFORMS STORED BY DQ7RFH.
+C DQ7RFH.... COMPUTES QR FACT. VIA HOUSEHOLDER TRANSFORMS WITH PIVOTING.
+C DR7MDC... RETURNS MACHINE-DEP. CONSTANTS.
+C DS7CPR... PRINTS LINEAR PARAMETERS AT SOLUTION.
+C DV2AXY.... ADDS MULTIPLE OF ONE VECTOR TO ANOTHER.
+C DV7CPY.... COPIES ONE VECTOR TO ANOTHER.
+C DV7PRM.... PERMUTES VECTOR.
+C DV7SCL... SCALES AND COPIES ONE VECTOR TO ANOTHER.
+C
+C  ***  LOCAL VARIABLES  ***
+C
+      INTEGER AR1, CSAVE1, D1, DR1, DR1L, I, I1,
+     1        IPIV1, IER, IV1, J1, JLEN, K, LL1O2, MD, N1, N2,
+     2        NML, NRAN, R1, R1L, RD1
+      DOUBLE PRECISION SINGTL, T
+      DOUBLE PRECISION MACHEP, NEGONE, SNGFAC, ZERO
+C
+C  ***  SUBSCRIPTS FOR IV AND V  ***
+C
+      INTEGER AR, CSAVE, D, IERS, IPIVS, IV1SAV,
+     2        IVNEED, J, MODE, NEXTIV, NEXTV,
+     2        NFCALL, NFGCAL, PERM, R,
+     3        REGD, REGD0, RESTOR, TOOBIG, VNEED
+C
+C  ***  IV SUBSCRIPT VALUES  ***
+C
+      PARAMETER (AR=110, CSAVE=105, D=27, IERS=108, IPIVS=109,
+     1           IV1SAV=104, IVNEED=3, J=70, MODE=35, NEXTIV=46,
+     2           NEXTV=47, NFCALL=6, NFGCAL=7, PERM=58, R=61, REGD=67,
+     3           REGD0=82, RESTOR=9, TOOBIG=2, VNEED=4)
+      DATA MACHEP/-1.D+0/, NEGONE/-1.D+0/, SNGFAC/1.D+2/, ZERO/0.D+0/
+C
+C++++++++++++++++++++++++++++++++  BODY  ++++++++++++++++++++++++++++++
+C
+C
+      IF (IV(1) .EQ. 0) CALL DIVSET(1, IV, LIV, LV, V)
+      N1 = 1
+      NML = N
+      IV1 = IV(1)
+      IF (IV1 .LE. 2) GO TO 20
+C
+C  ***  CHECK INPUT INTEGERS  ***
+C
+      IF (P .LE. 0) GO TO 240
+      IF (L .LT. 0) GO TO 240
+      IF (N .LE. L) GO TO 240
+      IF (LA .LT. N) GO TO 240
+      IF (IV1 .LT. 12) GO TO 20
+      IF (IV1 .EQ. 14) GO TO 20
+      IF (IV1 .EQ. 12) IV(1) = 13
+C
+C  ***  FRESH START -- COMPUTE STORAGE REQUIREMENTS  ***
+C
+      IF (IV(1) .GT. 16) GO TO 240
+      LL1O2 = L*(L+1)/2
+      JLEN = N*P
+      I = L + P
+      IF (IV(1) .NE. 13) GO TO 10
+         IV(IVNEED) = IV(IVNEED) + L
+         IV(VNEED) = IV(VNEED) + P + 2*N + JLEN + LL1O2 + L
+ 10   IF (IV(PERM) .LE. AR) IV(PERM) = AR + 1
+      CALL DRN2GB(B, V, V, IV, LIV, LV, N, N, N1, NML, P, V, V, V, ALF)
+      IF (IV(1) .NE. 14) GO TO 999
+C
+C  ***  STORAGE ALLOCATION  ***
+C
+      IV(IPIVS) = IV(NEXTIV)
+      IV(NEXTIV) = IV(NEXTIV) + L
+      IV(D) = IV(NEXTV)
+      IV(REGD0) = IV(D) + P
+      IV(AR) = IV(REGD0) + N
+      IV(CSAVE) = IV(AR) + LL1O2
+      IV(J) = IV(CSAVE) + L
+      IV(R) = IV(J) + JLEN
+      IV(NEXTV) = IV(R) + N
+      IV(IERS) = 0
+      IF (IV1 .EQ. 13) GO TO 999
+C
+C  ***  SET POINTERS INTO IV AND V  ***
+C
+ 20   AR1 = IV(AR)
+      D1 = IV(D)
+      DR1 = IV(J)
+      DR1L = DR1 + L
+      R1 = IV(R)
+      R1L = R1 + L
+      RD1 = IV(REGD0)
+      CSAVE1 = IV(CSAVE)
+      NML = N - L
+      IF (IV1 .LE. 2) GO TO 50
+C
+ 30   N2 = NML
+      CALL DRN2GB(B, V(D1), V(DR1L), IV, LIV, LV, NML, N, N1, N2, P,
+     1            V(R1L), V(RD1), V, ALF)
+      IF (IABS(IV(RESTOR)-2) .EQ. 1 .AND. L .GT. 0)
+     1        CALL DV7CPY(L, C, V(CSAVE1))
+      IV1 = IV(1)
+      IF (IV1 .EQ. 2) GO TO 150
+      IF (IV1 .GT. 2) GO TO 230
+C
+C  ***  NEW FUNCTION VALUE (RESIDUAL) NEEDED  ***
+C
+      IV(IV1SAV) = IV(1)
+      IV(1) = IABS(IV1)
+      IF (IV(RESTOR) .EQ. 2 .AND. L .GT. 0) CALL DV7CPY(L, V(CSAVE1), C)
+      GO TO 999
+C
+C  ***  COMPUTE NEW RESIDUAL OR GRADIENT  ***
+C
+ 50   IV(1) = IV(IV1SAV)
+      MD = IV(MODE)
+      IF (MD .LE. 0) GO TO 60
+         NML = N
+         DR1L = DR1
+         R1L = R1
+ 60   IF (IV(TOOBIG) .NE. 0) GO TO 30
+      IF (IABS(IV1) .EQ. 2) GO TO 170
+C
+C  ***  COMPUTE NEW RESIDUAL  ***
+C
+      IF (L1 .LE. L) CALL DV7CPY(N, V(R1), Y)
+      IF (L1 .GT. L) CALL DV2AXY(N, V(R1), NEGONE, A(1,L1), Y)
+      IF (MD .GT. 0) GO TO 120
+      IER = 0
+      IF (L .LE. 0) GO TO 110
+      LL1O2 = L * (L + 1) / 2
+      IPIV1 = IV(IPIVS)
+      CALL DQ7RFH(IER, IV(IPIV1), N, LA, 0, L, A, V(AR1), LL1O2, C)
+C
+C *** DETERMINE NUMERICAL RANK OF A ***
+C
+      IF (MACHEP .LE. ZERO) MACHEP = DR7MDC(3)
+      SINGTL = SNGFAC * DBLE(MAX0(L,N)) * MACHEP
+      K = L
+      IF (IER .NE. 0) K = IER - 1
+ 70   IF (K .LE. 0) GO TO 90
+         T = DL7SVX(K, V(AR1), C, C)
+         IF (T .GT. ZERO) T = DL7SVN(K, V(AR1), C, C) / T
+         IF (T .GT. SINGTL) GO TO 80
+         K = K - 1
+         GO TO 70
+C
+C *** RECORD RANK IN IV(IERS)... IV(IERS) = 0 MEANS FULL RANK,
+C *** IV(IERS) .GT. 0 MEANS RANK IV(IERS) - 1.
+C
+ 80   IF (K .GE. L) GO TO 100
+ 90      IER = K + 1
+         CALL DV7SCP(L-K, C(K+1), ZERO)
+ 100  IV(IERS) = IER
+      IF (K .LE. 0) GO TO 110
+C
+C *** APPLY HOUSEHOLDER TRANSFORMATONS TO RESIDUALS...
+C
+      CALL DQ7APL(LA, N, K, A, V(R1), IER)
+C
+C *** COMPUTING C NOW MAY SAVE A FUNCTION EVALUATION AT
+C *** THE LAST ITERATION.
+C
+      CALL DL7ITV(K, C, V(AR1), V(R1))
+      CALL DV7PRM(L, IV(IPIV1), C)
+C
+ 110  IF(IV(1) .LT. 2) GO TO 220
+      GO TO 999
+C
+C
+C  ***  RESIDUAL COMPUTATION FOR F.D. HESSIAN  ***
+C
+ 120  IF (L .LE. 0) GO TO 140
+      DO 130 I = 1, L
+ 130     CALL DV2AXY(N, V(R1), -C(I), A(1,I), V(R1))
+ 140  IF (IV(1) .GT. 0) GO TO 30
+         IV(1) = 2
+         GO TO 160
+C
+C  ***  NEW GRADIENT (JACOBIAN) NEEDED  ***
+C
+ 150  IV(IV1SAV) = IV1
+      IF (IV(NFGCAL) .NE. IV(NFCALL)) IV(1) = 1
+ 160  CALL DV7SCP(N*P, V(DR1), ZERO)
+      GO TO 999
+C
+C  ***  COMPUTE NEW JACOBIAN  ***
+C
+ 170  IF (NDA .LE. 0) GO TO 240
+      DO 180 I = 1, NDA
+         I1 = IN(1,I) - 1
+         IF (I1 .LT. 0) GO TO 180
+         J1 = IN(2,I)
+         K = DR1 + I1*N
+         T = NEGONE
+         IF (J1 .LE. L) T = -C(J1)
+         CALL DV2AXY(N, V(K), T, DA(1,I), V(K))
+ 180     CONTINUE
+      IF (IV1 .EQ. 2) GO TO 190
+         IV(1) = IV1
+         GO TO 999
+ 190  IF (L .LE. 0) GO TO 30
+      IF (MD .GT. 0) GO TO 30
+      K = DR1
+      IER = IV(IERS)
+      NRAN = L
+      IF (IER .GT. 0) NRAN = IER - 1
+      IF (NRAN .LE. 0) GO TO 210
+      DO 200 I = 1, P
+         CALL DQ7APL(LA, N, NRAN, A, V(K), IER)
+         K = K + N
+ 200     CONTINUE
+ 210  CALL DV7CPY(L, V(CSAVE1), C)
+ 220  IF (IER .EQ. 0) GO TO 30
+C
+C     *** ADJUST SUBSCRIPTS DESCRIBING R AND DR...
+C
+         NRAN = IER - 1
+         DR1L = DR1 + NRAN
+         NML = N - NRAN
+         R1L = R1 + NRAN
+         GO TO 30
+C
+C  ***  CONVERGENCE OR LIMIT REACHED  ***
+C
+ 230  IF (IV(REGD) .EQ. 1) IV(REGD) = RD1
+      IF (IV(1) .LE. 11) CALL DS7CPR(C, IV, L, LIV)
+      GO TO 999
+C
+ 240  IV(1) = 66
+      CALL DITSUM(V, V, IV, LIV, LV, P, V, ALF)
+C
+ 999  RETURN
+C
+C  ***  LAST CARD OF DRNSGB FOLLOWS  ***
+      END
+      SUBROUTINE DS7LUP(A, COSMIN, P, SIZE, STEP, U, W, WCHMTD, WSCALE,
+     1                  Y)
+C
+C  ***  UPDATE SYMMETRIC  A  SO THAT  A * STEP = Y  ***
+C  ***  (LOWER TRIANGLE OF  A  STORED ROWWISE       ***
+C
+C  ***  PARAMETER DECLARATIONS  ***
+C
+      INTEGER P
+      DOUBLE PRECISION A(*), COSMIN, SIZE, STEP(P), U(P), W(P),
+     1                 WCHMTD(P), WSCALE, Y(P)
+C     DIMENSION A(P*(P+1)/2)
+C
+C  ***  LOCAL VARIABLES  ***
+C
+      INTEGER I, J, K
+      DOUBLE PRECISION DENMIN, SDOTWM, T, UI, WI
+C
+C     ***  CONSTANTS  ***
+      DOUBLE PRECISION HALF, ONE, ZERO
+C
+C  ***  EXTERNAL FUNCTIONS AND SUBROUTINES  ***
+C
+      DOUBLE PRECISION DD7TPR, DV2NRM
+      EXTERNAL DD7TPR, DS7LVM, DV2NRM
+C
+      PARAMETER (HALF=0.5D+0, ONE=1.D+0, ZERO=0.D+0)
+C
+C-----------------------------------------------------------------------
+C
+      SDOTWM = DD7TPR(P, STEP, WCHMTD)
+      DENMIN = COSMIN * DV2NRM(P,STEP) * DV2NRM(P,WCHMTD)
+      WSCALE = ONE
+      IF (DENMIN .NE. ZERO) WSCALE = DMIN1(ONE, DABS(SDOTWM/DENMIN))
+      T = ZERO
+      IF (SDOTWM .NE. ZERO) T = WSCALE / SDOTWM
+      DO 10 I = 1, P
+ 10      W(I) = T * WCHMTD(I)
+      CALL DS7LVM(P, U, A, STEP)
+      T = HALF * (SIZE * DD7TPR(P, STEP, U)  -  DD7TPR(P, STEP, Y))
+      DO 20 I = 1, P
+ 20      U(I) = T*W(I) + Y(I) - SIZE*U(I)
+C
+C  ***  SET  A = A + U*(W**T) + W*(U**T)  ***
+C
+      K = 1
+      DO 40 I = 1, P
+         UI = U(I)
+         WI = W(I)
+         DO 30 J = 1, I
+              A(K) = SIZE*A(K) + UI*W(J) + WI*U(J)
+              K = K + 1
+ 30           CONTINUE
+ 40      CONTINUE
+C
+      RETURN
+C  ***  LAST CARD OF DS7LUP FOLLOWS  ***
+      END
+      SUBROUTINE DL7MST(D, G, IERR, IPIVOT, KA, P, QTR, R, STEP, V, W)
+C
+C  ***  COMPUTE LEVENBERG-MARQUARDT STEP USING MORE-HEBDEN TECHNIQUE  **
+C  ***  NL2SOL VERSION 2.2.  ***
+C
+C  ***  PARAMETER DECLARATIONS  ***
+C
+      INTEGER IERR, KA, P
+      INTEGER IPIVOT(P)
+      DOUBLE PRECISION D(P), G(P), QTR(P), R(*), STEP(P), V(21), W(*)
+C     DIMENSION W(P*(P+5)/2 + 4)
+C
+C+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+C
+C  ***  PURPOSE  ***
+C
+C        GIVEN THE R MATRIX FROM THE QR DECOMPOSITION OF A JACOBIAN
+C     MATRIX, J, AS WELL AS Q-TRANSPOSE TIMES THE CORRESPONDING
+C     RESIDUAL VECTOR, RESID, THIS SUBROUTINE COMPUTES A LEVENBERG-
+C     MARQUARDT STEP OF APPROXIMATE LENGTH V(RADIUS) BY THE MORE-
+C     TECHNIQUE.
+C
+C  ***  PARAMETER DESCRIPTION  ***
+C
+C      D (IN)  = THE SCALE VECTOR.
+C      G (IN)  = THE GRADIENT VECTOR (J**T)*R.
+C   IERR (I/O) = RETURN CODE FROM QRFACT OR DQ7RGS -- 0 MEANS R HAS
+C             FULL RANK.
+C IPIVOT (I/O) = PERMUTATION ARRAY FROM QRFACT OR DQ7RGS, WHICH COMPUTE
+C             QR DECOMPOSITIONS WITH COLUMN PIVOTING.
+C     KA (I/O).  KA .LT. 0 ON INPUT MEANS THIS IS THE FIRST CALL ON
+C             DL7MST FOR THE CURRENT R AND QTR.  ON OUTPUT KA CON-
+C             TAINS THE NUMBER OF HEBDEN ITERATIONS NEEDED TO DETERMINE
+C             STEP.  KA = 0 MEANS A GAUSS-NEWTON STEP.
+C      P (IN)  = NUMBER OF PARAMETERS.
+C    QTR (IN)  = (Q**T)*RESID = Q-TRANSPOSE TIMES THE RESIDUAL VECTOR.
+C      R (IN)  = THE R MATRIX, STORED COMPACTLY BY COLUMNS.
+C   STEP (OUT) = THE LEVENBERG-MARQUARDT STEP COMPUTED.
+C      V (I/O) CONTAINS VARIOUS CONSTANTS AND VARIABLES DESCRIBED BELOW.
+C      W (I/O) = WORKSPACE OF LENGTH P*(P+5)/2 + 4.
+C
+C  ***  ENTRIES IN V  ***
+C
+C V(DGNORM) (I/O) = 2-NORM OF (D**-1)*G.
+C V(DSTNRM) (I/O) = 2-NORM OF D*STEP.
+C V(DST0)   (I/O) = 2-NORM OF GAUSS-NEWTON STEP (FOR NONSING. J).
+C V(EPSLON) (IN) = MAX. REL. ERROR ALLOWED IN TWONORM(R)**2 MINUS
+C             TWONORM(R - J*STEP)**2.  (SEE ALGORITHM NOTES BELOW.)
+C V(GTSTEP) (OUT) = INNER PRODUCT BETWEEN G AND STEP.
+C V(NREDUC) (OUT) = HALF THE REDUCTION IN THE SUM OF SQUARES PREDICTED
+C             FOR A GAUSS-NEWTON STEP.
+C V(PHMNFC) (IN)  = TOL. (TOGETHER WITH V(PHMXFC)) FOR ACCEPTING STEP
+C             (MORE*S SIGMA).  THE ERROR V(DSTNRM) - V(RADIUS) MUST LIE
+C             BETWEEN V(PHMNFC)*V(RADIUS) AND V(PHMXFC)*V(RADIUS).
+C V(PHMXFC) (IN)  (SEE V(PHMNFC).)
+C V(PREDUC) (OUT) = HALF THE REDUCTION IN THE SUM OF SQUARES PREDICTED
+C             BY THE STEP RETURNED.
+C V(RADIUS) (IN)  = RADIUS OF CURRENT (SCALED) TRUST REGION.
+C V(RAD0)   (I/O) = VALUE OF V(RADIUS) FROM PREVIOUS CALL.
+C V(STPPAR) (I/O) = MARQUARDT PARAMETER (OR ITS NEGATIVE IF THE SPECIAL
+C             CASE MENTIONED BELOW IN THE ALGORITHM NOTES OCCURS).
+C
+C NOTE -- SEE DATA STATEMENT BELOW FOR VALUES OF ABOVE SUBSCRIPTS.
+C
+C  ***  USAGE NOTES  ***
+C
+C     IF IT IS DESIRED TO RECOMPUTE STEP USING A DIFFERENT VALUE OF
+C     V(RADIUS), THEN THIS ROUTINE MAY BE RESTARTED BY CALLING IT
+C     WITH ALL PARAMETERS UNCHANGED EXCEPT V(RADIUS).  (THIS EXPLAINS
+C     WHY MANY PARAMETERS ARE LISTED AS I/O).  ON AN INTIIAL CALL (ONE
+C     WITH KA = -1), THE CALLER NEED ONLY HAVE INITIALIZED D, G, KA, P,
+C     QTR, R, V(EPSLON), V(PHMNFC), V(PHMXFC), V(RADIUS), AND V(RAD0).
+C
+C  ***  APPLICATION AND USAGE RESTRICTIONS  ***
+C
+C     THIS ROUTINE IS CALLED AS PART OF THE NL2SOL (NONLINEAR LEAST-
+C     SQUARES) PACKAGE (REF. 1).
+C
+C  ***  ALGORITHM NOTES  ***
+C
+C     THIS CODE IMPLEMENTS THE STEP COMPUTATION SCHEME DESCRIBED IN
+C     REFS. 2 AND 4.  FAST GIVENS TRANSFORMATIONS (SEE REF. 3, PP. 60-
+C     62) ARE USED TO COMPUTE STEP WITH A NONZERO MARQUARDT PARAMETER.
+C        A SPECIAL CASE OCCURS IF J IS (NEARLY) SINGULAR AND V(RADIUS)
+C     IS SUFFICIENTLY LARGE.  IN THIS CASE THE STEP RETURNED IS SUCH
+C     THAT  TWONORM(R)**2 - TWONORM(R - J*STEP)**2  DIFFERS FROM ITS
+C     OPTIMAL VALUE BY LESS THAN V(EPSLON) TIMES THIS OPTIMAL VALUE,
+C     WHERE J AND R DENOTE THE ORIGINAL JACOBIAN AND RESIDUAL.  (SEE
+C     REF. 2 FOR MORE DETAILS.)
+C
+C  ***  FUNCTIONS AND SUBROUTINES CALLED  ***
+C
+C DD7TPR - RETURNS INNER PRODUCT OF TWO VECTORS.
+C DL7ITV - APPLY INVERSE-TRANSPOSE OF COMPACT LOWER TRIANG. MATRIX.
+C DL7IVM - APPLY INVERSE OF COMPACT LOWER TRIANG. MATRIX.
+C DV7CPY  - COPIES ONE VECTOR TO ANOTHER.
+C DV2NRM - RETURNS 2-NORM OF A VECTOR.
+C
+C  ***  REFERENCES  ***
+C
+C 1.  DENNIS, J.E., GAY, D.M., AND WELSCH, R.E. (1981), AN ADAPTIVE
+C             NONLINEAR LEAST-SQUARES ALGORITHM, ACM TRANS. MATH.
+C             SOFTWARE, VOL. 7, NO. 3.
+C 2.  GAY, D.M. (1981), COMPUTING OPTIMAL LOCALLY CONSTRAINED STEPS,
+C             SIAM J. SCI. STATIST. COMPUTING, VOL. 2, NO. 2, PP.
+C             186-197.
+C 3.  LAWSON, C.L., AND HANSON, R.J. (1974), SOLVING LEAST SQUARES
+C             PROBLEMS, PRENTICE-HALL, ENGLEWOOD CLIFFS, N.J.
+C 4.  MORE, J.J. (1978), THE LEVENBERG-MARQUARDT ALGORITHM, IMPLEMEN-
+C             TATION AND THEORY, PP.105-116 OF SPRINGER LECTURE NOTES
+C             IN MATHEMATICS NO. 630, EDITED BY G.A. WATSON, SPRINGER-
+C             VERLAG, BERLIN AND NEW YORK.
+C
+C  ***  GENERAL  ***
+C
+C     CODED BY DAVID M. GAY.
+C     THIS SUBROUTINE WAS WRITTEN IN CONNECTION WITH RESEARCH
+C     SUPPORTED BY THE NATIONAL SCIENCE FOUNDATION UNDER GRANTS
+C     MCS-7600324, DCR75-10143, 76-14311DSS, MCS76-11989, AND
+C     MCS-7906671.
+C
+C+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+C
+C  ***  LOCAL VARIABLES  ***
+C
+      INTEGER DSTSAV, I, IP1, I1, J1, K, KALIM, L, LK0, PHIPIN,
+     1        PP1O2, RES, RES0, RMAT, RMAT0, UK0
+      DOUBLE PRECISION A, ADI, ALPHAK, B, DFACSQ, DST, DTOL, D1, D2,
+     1                 LK, OLDPHI, PHI, PHIMAX, PHIMIN, PSIFAC, RAD,
+     2                 SI, SJ, SQRTAK, T, TWOPSI, UK, WL
+C
+C     ***  CONSTANTS  ***
+      DOUBLE PRECISION DFAC, EIGHT, HALF, NEGONE, ONE, P001, THREE,
+     1                 TTOL, ZERO
+      DOUBLE PRECISION BIG
+C
+C  ***  INTRINSIC FUNCTIONS  ***
+C/+
+      DOUBLE PRECISION DSQRT
+C/
+C  ***  EXTERNAL FUNCTIONS AND SUBROUTINES  ***
+C
+      DOUBLE PRECISION DD7TPR, DL7SVN, DR7MDC, DV2NRM
+      EXTERNAL DD7TPR, DL7ITV, DL7IVM, DL7SVN, DR7MDC,DV7CPY, DV2NRM
+C
+C  ***  SUBSCRIPTS FOR V  ***
+C
+      INTEGER DGNORM, DSTNRM, DST0, EPSLON, GTSTEP, NREDUC, PHMNFC,
+     1        PHMXFC, PREDUC, RADIUS, RAD0, STPPAR
+      PARAMETER (DGNORM=1, DSTNRM=2, DST0=3, EPSLON=19, GTSTEP=4,
+     1           NREDUC=6, PHMNFC=20, PHMXFC=21, PREDUC=7, RADIUS=8,
+     2           RAD0=9, STPPAR=5)
+C
+      PARAMETER (DFAC=256.D+0, EIGHT=8.D+0, HALF=0.5D+0, NEGONE=-1.D+0,
+     1     ONE=1.D+0, P001=1.D-3, THREE=3.D+0, TTOL=2.5D+0,
+     2     ZERO=0.D+0)
+      SAVE BIG
+      DATA BIG/0.D+0/
+C
+C  ***  BODY  ***
+C
+C     ***  FOR USE IN RECOMPUTING STEP, THE FINAL VALUES OF LK AND UK,
+C     ***  THE INVERSE DERIVATIVE OF MORE*S PHI AT 0 (FOR NONSING. J)
+C     ***  AND THE VALUE RETURNED AS V(DSTNRM) ARE STORED AT W(LK0),
+C     ***  W(UK0), W(PHIPIN), AND W(DSTSAV) RESPECTIVELY.
+      LK0 = P + 1
+      PHIPIN = LK0 + 1
+      UK0 = PHIPIN + 1
+      DSTSAV = UK0 + 1
+      RMAT0 = DSTSAV
+C     ***  A COPY OF THE R-MATRIX FROM THE QR DECOMPOSITION OF J IS
+C     ***  STORED IN W STARTING AT W(RMAT), AND A COPY OF THE RESIDUAL
+C     ***  VECTOR IS STORED IN W STARTING AT W(RES).  THE LOOPS BELOW
+C     ***  THAT UPDATE THE QR DECOMP. FOR A NONZERO MARQUARDT PARAMETER
+C     ***  WORK ON THESE COPIES.
+      RMAT = RMAT0 + 1
+      PP1O2 = P * (P + 1) / 2
+      RES0 = PP1O2 + RMAT0
+      RES = RES0 + 1
+      RAD = V(RADIUS)
+      IF (RAD .GT. ZERO)
+     1   PSIFAC = V(EPSLON)/((EIGHT*(V(PHMNFC) + ONE) + THREE) * RAD**2)
+      IF (BIG .LE. ZERO) BIG = DR7MDC(6)
+      PHIMAX = V(PHMXFC) * RAD
+      PHIMIN = V(PHMNFC) * RAD
+C     ***  DTOL, DFAC, AND DFACSQ ARE USED IN RESCALING THE FAST GIVENS
+C     ***  REPRESENTATION OF THE UPDATED QR DECOMPOSITION.
+      DTOL = ONE/DFAC
+      DFACSQ = DFAC*DFAC
+C     ***  OLDPHI IS USED TO DETECT LIMITS OF NUMERICAL ACCURACY.  IF
+C     ***  WE RECOMPUTE STEP AND IT DOES NOT CHANGE, THEN WE ACCEPT IT.
+      OLDPHI = ZERO
+      LK = ZERO
+      UK = ZERO
+      KALIM = KA + 12
+C
+C  ***  START OR RESTART, DEPENDING ON KA  ***
+C
+      IF (KA .EQ. 0) GO TO 20
+      IF (KA .GT. 0) GO TO 370
+C
+C  ***  FRESH START -- COMPUTE V(NREDUC)  ***
+C
+      KA = 0
+      KALIM = 12
+      K = P
+      IF (IERR .NE. 0) K = IABS(IERR) - 1
+      V(NREDUC) = HALF*DD7TPR(K, QTR, QTR)
+C
+C  ***  SET UP TO TRY INITIAL GAUSS-NEWTON STEP  ***
+C
+ 20   V(DST0) = NEGONE
+      IF (IERR .NE. 0) GO TO 90
+      T = DL7SVN(P, R, STEP, W(RES))
+      IF (T .GE. ONE) GO TO 30
+         IF (DV2NRM(P, QTR) .GE. BIG*T) GO TO 90
+C
+C  ***  COMPUTE GAUSS-NEWTON STEP  ***
+C
+C     ***  NOTE -- THE R-MATRIX IS STORED COMPACTLY BY COLUMNS IN
+C     ***  R(1), R(2), R(3), ...  IT IS THE TRANSPOSE OF A
+C     ***  LOWER TRIANGULAR MATRIX STORED COMPACTLY BY ROWS, AND WE
+C     ***  TREAT IT AS SUCH WHEN USING DL7ITV AND DL7IVM.
+ 30   CALL DL7ITV(P, W, R, QTR)
+C     ***  TEMPORARILY STORE PERMUTED -D*STEP IN STEP.
+      DO 60 I = 1, P
+         J1 = IPIVOT(I)
+         STEP(I) = D(J1)*W(I)
+ 60      CONTINUE
+      DST = DV2NRM(P, STEP)
+      V(DST0) = DST
+      PHI = DST - RAD
+      IF (PHI .LE. PHIMAX) GO TO 410
+C     ***  IF THIS IS A RESTART, GO TO 110  ***
+      IF (KA .GT. 0) GO TO 110
+C
+C  ***  GAUSS-NEWTON STEP WAS UNACCEPTABLE.  COMPUTE L0  ***
+C
+      DO 70 I = 1, P
+         J1 = IPIVOT(I)
+         STEP(I) = D(J1)*(STEP(I)/DST)
+ 70      CONTINUE
+      CALL DL7IVM(P, STEP, R, STEP)
+      T = ONE / DV2NRM(P, STEP)
+      W(PHIPIN) = (T/RAD)*T
+      LK = PHI*W(PHIPIN)
+C
+C  ***  COMPUTE U0  ***
+C
+ 90   DO 100 I = 1, P
+ 100     W(I) = G(I)/D(I)
+      V(DGNORM) = DV2NRM(P, W)
+      UK = V(DGNORM)/RAD
+      IF (UK .LE. ZERO) GO TO 390
+C
+C     ***  ALPHAK WILL BE USED AS THE CURRENT MARQUARDT PARAMETER.  WE
+C     ***  USE MORE*S SCHEME FOR INITIALIZING IT.
+C
+      ALPHAK = DABS(V(STPPAR)) * V(RAD0)/RAD
+      ALPHAK = DMIN1(UK, DMAX1(ALPHAK, LK))
+C
+C
+C  ***  TOP OF LOOP -- INCREMENT KA, COPY R TO RMAT, QTR TO RES  ***
+C
+ 110  KA = KA + 1
+      CALL DV7CPY(PP1O2, W(RMAT), R)
+      CALL DV7CPY(P, W(RES), QTR)
+C
+C  ***  SAFEGUARD ALPHAK AND INITIALIZE FAST GIVENS SCALE VECTOR.  ***
+C
+      IF (ALPHAK .LE. ZERO .OR. ALPHAK .LT. LK .OR. ALPHAK .GE. UK)
+     1             ALPHAK = UK * DMAX1(P001, DSQRT(LK/UK))
+      IF (ALPHAK .LE. ZERO) ALPHAK = HALF * UK
+      SQRTAK = DSQRT(ALPHAK)
+      DO 120 I = 1, P
+ 120     W(I) = ONE
+C
+C  ***  ADD ALPHAK*D AND UPDATE QR DECOMP. USING FAST GIVENS TRANS.  ***
+C
+      DO 270 I = 1, P
+C        ***  GENERATE, APPLY 1ST GIVENS TRANS. FOR ROW I OF ALPHAK*D.
+C        ***  (USE STEP TO STORE TEMPORARY ROW)  ***
+         L = I*(I+1)/2 + RMAT0
+         WL = W(L)
+         D2 = ONE
+         D1 = W(I)
+         J1 = IPIVOT(I)
+         ADI = SQRTAK*D(J1)
+         IF (ADI .GE. DABS(WL)) GO TO 150
+ 130     A = ADI/WL
+         B = D2*A/D1
+         T = A*B + ONE
+         IF (T .GT. TTOL) GO TO 150
+         W(I) = D1/T
+         D2 = D2/T
+         W(L) = T*WL
+         A = -A
+         DO 140 J1 = I, P
+              L = L + J1
+              STEP(J1) = A*W(L)
+ 140          CONTINUE
+         GO TO 170
+C
+ 150     B = WL/ADI
+         A = D1*B/D2
+         T = A*B + ONE
+         IF (T .GT. TTOL) GO TO 130
+         W(I) = D2/T
+         D2 = D1/T
+         W(L) = T*ADI
+         DO 160 J1 = I, P
+              L = L + J1
+              WL = W(L)
+              STEP(J1) = -WL
+              W(L) = A*WL
+ 160          CONTINUE
+C
+ 170     IF (I .EQ. P) GO TO 280
+C
+C        ***  NOW USE GIVENS TRANS. TO ZERO ELEMENTS OF TEMP. ROW  ***
+C
+         IP1 = I + 1
+         DO 260 I1 = IP1, P
+              SI = STEP(I1-1)
+              IF (SI .EQ. ZERO) GO TO 260
+              L = I1*(I1+1)/2 + RMAT0
+              WL = W(L)
+              D1 = W(I1)
+C
+C             ***  RESCALE ROW I1 IF NECESSARY  ***
+C
+              IF (D1 .GE. DTOL) GO TO 190
+                   D1 = D1*DFACSQ
+                   WL = WL/DFAC
+                   K = L
+                   DO 180 J1 = I1, P
+                        K = K + J1
+                        W(K) = W(K)/DFAC
+ 180                    CONTINUE
+C
+C             ***  USE GIVENS TRANS. TO ZERO NEXT ELEMENT OF TEMP. ROW
+C
+ 190          IF (DABS(SI) .GT. DABS(WL)) GO TO 220
+ 200          A = SI/WL
+              B = D2*A/D1
+              T = A*B + ONE
+              IF (T .GT. TTOL) GO TO 220
+              W(L) = T*WL
+              W(I1) = D1/T
+              D2 = D2/T
+              DO 210 J1 = I1, P
+                   L = L + J1
+                   WL = W(L)
+                   SJ = STEP(J1)
+                   W(L) = WL + B*SJ
+                   STEP(J1) = SJ - A*WL
+ 210               CONTINUE
+              GO TO 240
+C
+ 220          B = WL/SI
+              A = D1*B/D2
+              T = A*B + ONE
+              IF (T .GT. TTOL) GO TO 200
+              W(I1) = D2/T
+              D2 = D1/T
+              W(L) = T*SI
+              DO 230 J1 = I1, P
+                   L = L + J1
+                   WL = W(L)
+                   SJ = STEP(J1)
+                   W(L) = A*WL + SJ
+                   STEP(J1) = B*SJ - WL
+ 230               CONTINUE
+C
+C             ***  RESCALE TEMP. ROW IF NECESSARY  ***
+C
+ 240          IF (D2 .GE. DTOL) GO TO 260
+                   D2 = D2*DFACSQ
+                   DO 250 K = I1, P
+ 250                    STEP(K) = STEP(K)/DFAC
+ 260          CONTINUE
+ 270     CONTINUE
+C
+C  ***  COMPUTE STEP  ***
+C
+ 280  CALL DL7ITV(P, W(RES), W(RMAT), W(RES))
+C     ***  RECOVER STEP AND STORE PERMUTED -D*STEP AT W(RES)  ***
+      DO 290 I = 1, P
+         J1 = IPIVOT(I)
+         K = RES0 + I
+         T = W(K)
+         STEP(J1) = -T
+         W(K) = T*D(J1)
+ 290     CONTINUE
+      DST = DV2NRM(P, W(RES))
+      PHI = DST - RAD
+      IF (PHI .LE. PHIMAX .AND. PHI .GE. PHIMIN) GO TO 430
+      IF (OLDPHI .EQ. PHI) GO TO 430
+      OLDPHI = PHI
+C
+C  ***  CHECK FOR (AND HANDLE) SPECIAL CASE  ***
+C
+      IF (PHI .GT. ZERO) GO TO 310
+         IF (KA .GE. KALIM) GO TO 430
+              TWOPSI = ALPHAK*DST*DST - DD7TPR(P, STEP, G)
+              IF (ALPHAK .GE. TWOPSI*PSIFAC) GO TO 310
+                   V(STPPAR) = -ALPHAK
+                   GO TO 440
+C
+C  ***  UNACCEPTABLE STEP -- UPDATE LK, UK, ALPHAK, AND TRY AGAIN  ***
+C
+ 300  IF (PHI .LT. ZERO) UK = DMIN1(UK, ALPHAK)
+      GO TO 320
+ 310  IF (PHI .LT. ZERO) UK = ALPHAK
+ 320  DO 330 I = 1, P
+         J1 = IPIVOT(I)
+         K = RES0 + I
+         STEP(I) = D(J1) * (W(K)/DST)
+ 330     CONTINUE
+      CALL DL7IVM(P, STEP, W(RMAT), STEP)
+      DO 340 I = 1, P
+ 340     STEP(I) = STEP(I) / DSQRT(W(I))
+      T = ONE / DV2NRM(P, STEP)
+      ALPHAK = ALPHAK + T*PHI*T/RAD
+      LK = DMAX1(LK, ALPHAK)
+      ALPHAK = LK
+      GO TO 110
+C
+C  ***  RESTART  ***
+C
+ 370  LK = W(LK0)
+      UK = W(UK0)
+      IF (V(DST0) .GT. ZERO .AND. V(DST0) - RAD .LE. PHIMAX) GO TO 20
+      ALPHAK = DABS(V(STPPAR))
+      DST = W(DSTSAV)
+      PHI = DST - RAD
+      T = V(DGNORM)/RAD
+      IF (RAD .GT. V(RAD0)) GO TO 380
+C
+C        ***  SMALLER RADIUS  ***
+         UK = T
+         IF (ALPHAK .LE. ZERO) LK = ZERO
+         IF (V(DST0) .GT. ZERO) LK = DMAX1(LK, (V(DST0)-RAD)*W(PHIPIN))
+         GO TO 300
+C
+C     ***  BIGGER RADIUS  ***
+ 380  IF (ALPHAK .LE. ZERO .OR. UK .GT. T) UK = T
+      LK = ZERO
+      IF (V(DST0) .GT. ZERO) LK = DMAX1(LK, (V(DST0)-RAD)*W(PHIPIN))
+      GO TO 300
+C
+C  ***  SPECIAL CASE -- RAD .LE. 0 OR (G = 0 AND J IS SINGULAR)  ***
+C
+ 390  V(STPPAR) = ZERO
+      DST = ZERO
+      LK = ZERO
+      UK = ZERO
+      V(GTSTEP) = ZERO
+      V(PREDUC) = ZERO
+      DO 400 I = 1, P
+ 400     STEP(I) = ZERO
+      GO TO 450
+C
+C  ***  ACCEPTABLE GAUSS-NEWTON STEP -- RECOVER STEP FROM W  ***
+C
+ 410  ALPHAK = ZERO
+      DO 420 I = 1, P
+         J1 = IPIVOT(I)
+         STEP(J1) = -W(I)
+ 420     CONTINUE
+C
+C  ***  SAVE VALUES FOR USE IN A POSSIBLE RESTART  ***
+C
+ 430  V(STPPAR) = ALPHAK
+ 440  V(GTSTEP) = DMIN1(DD7TPR(P,STEP,G), ZERO)
+      V(PREDUC) = HALF * (ALPHAK*DST*DST - V(GTSTEP))
+ 450  V(DSTNRM) = DST
+      W(DSTSAV) = DST
+      W(LK0) = LK
+      W(UK0) = UK
+      V(RAD0) = RAD
+C
+      RETURN
+C
+C  ***  LAST CARD OF DL7MST FOLLOWS  ***
+      END
+      SUBROUTINE DRMNFB(B, D, FX, IV, LIV, LV, P, V, X)
+C
+C  ***  ITERATION DRIVER FOR  DMNF...
+C  ***  MINIMIZE GENERAL UNCONSTRAINED OBJECTIVE FUNCTION USING
+C  ***  FINITE-DIFFERENCE GRADIENTS AND SECANT HESSIAN APPROXIMATIONS.
+C
+      INTEGER LIV, LV, P
+      INTEGER IV(LIV)
+      DOUBLE PRECISION B(2,P), D(P), FX, X(P), V(LV)
+C     DIMENSION IV(59 + P), V(77 + P*(P+23)/2)
+C
+C  ***  PURPOSE  ***
+C
+C        THIS ROUTINE INTERACTS WITH SUBROUTINE  DRMNGB  IN AN ATTEMPT
+C     TO FIND AN P-VECTOR  X*  THAT MINIMIZES THE (UNCONSTRAINED)
+C     OBJECTIVE FUNCTION  FX = F(X)  COMPUTED BY THE CALLER.  (OFTEN
+C     THE  X*  FOUND IS A LOCAL MINIMIZER RATHER THAN A GLOBAL ONE.)
+C
+C  ***  PARAMETERS  ***
+C
+C        THE PARAMETERS FOR DRMNFB ARE THE SAME AS THOSE FOR  DMNG
+C     (WHICH SEE), EXCEPT THAT CALCF, CALCG, UIPARM, URPARM, AND UFPARM
+C     ARE OMITTED, AND A PARAMETER  FX  FOR THE OBJECTIVE FUNCTION
+C     VALUE AT X IS ADDED.  INSTEAD OF CALLING CALCG TO OBTAIN THE
+C     GRADIENT OF THE OBJECTIVE FUNCTION AT X, DRMNFB CALLS DS3GRD,
+C     WHICH COMPUTES AN APPROXIMATION TO THE GRADIENT BY FINITE
+C     (FORWARD AND CENTRAL) DIFFERENCES USING THE METHOD OF REF. 1.
+C     THE FOLLOWING INPUT COMPONENT IS OF INTEREST IN THIS REGARD
+C     (AND IS NOT DESCRIBED IN  DMNG).
+C
+C V(ETA0)..... V(42) IS AN ESTIMATED BOUND ON THE RELATIVE ERROR IN THE
+C             OBJECTIVE FUNCTION VALUE COMPUTED BY CALCF...
+C                  (TRUE VALUE) = (COMPUTED VALUE) * (1 + E),
+C             WHERE ABS(E) .LE. V(ETA0).  DEFAULT = MACHEP * 10**3,
+C             WHERE MACHEP IS THE UNIT ROUNDOFF.
+C
+C        THE OUTPUT VALUES IV(NFCALL) AND IV(NGCALL) HAVE DIFFERENT
+C     MEANINGS FOR  DMNF THAN FOR  DMNG...
+C
+C IV(NFCALL)... IV(6) IS THE NUMBER OF CALLS SO FAR MADE ON CALCF (I.E.,
+C             FUNCTION EVALUATIONS) EXCLUDING THOSE MADE ONLY FOR
+C             COMPUTING GRADIENTS.  THE INPUT VALUE IV(MXFCAL) IS A
+C             LIMIT ON IV(NFCALL).
+C IV(NGCALL)... IV(30) IS THE NUMBER OF FUNCTION EVALUATIONS MADE ONLY
+C             FOR COMPUTING GRADIENTS.  THE TOTAL NUMBER OF FUNCTION
+C             EVALUATIONS IS THUS  IV(NFCALL) + IV(NGCALL).
+C
+C  ***  REFERENCES  ***
+C
+C 1. STEWART, G.W. (1967), A MODIFICATION OF DAVIDON*S MINIMIZATION
+C        METHOD TO ACCEPT DIFFERENCE APPROXIMATIONS OF DERIVATIVES,
+C        J. ASSOC. COMPUT. MACH. 14, PP. 72-83.
+C.
+C  ***  GENERAL  ***
+C
+C     CODED BY DAVID M. GAY (AUGUST 1982).
+C
+C----------------------------  DECLARATIONS  ---------------------------
+C
+      DOUBLE PRECISION DD7TPR
+      EXTERNAL DIVSET, DD7TPR, DS3GRD, DRMNGB, DV7SCP
+C
+C DIVSET.... SUPPLIES DEFAULT PARAMETER VALUES.
+C DD7TPR... RETURNS INNER PRODUCT OF TWO VECTORS.
+C DS3GRD... COMPUTES FINITE-DIFFERENCE GRADIENT APPROXIMATION.
+C DRMNGB... REVERSE-COMMUNICATION ROUTINE THAT DOES  DMNGB ALGORITHM.
+C DV7SCP... SETS ALL ELEMENTS OF A VECTOR TO A SCALAR.
+C
+      INTEGER ALPHA, ALPHA0, G1, I, IPI, IV1, J, K, W
+      DOUBLE PRECISION ZERO
+C
+C  ***  SUBSCRIPTS FOR IV   ***
+C
+      INTEGER ETA0, F, G, LMAT, NEXTV, NGCALL,
+     1        NITER, PERM, SGIRC, TOOBIG, VNEED
+C
+      PARAMETER (ETA0=42, F=10, G=28, LMAT=42, NEXTV=47, NGCALL=30,
+     1           NITER=31, PERM=58, SGIRC=57, TOOBIG=2, VNEED=4)
+      PARAMETER (ZERO=0.D+0)
+C
+C+++++++++++++++++++++++++++++++  BODY  ++++++++++++++++++++++++++++++++
+C
+      IV1 = IV(1)
+      IF (IV1 .EQ. 1) GO TO 10
+      IF (IV1 .EQ. 2) GO TO 50
+      IF (IV(1) .EQ. 0) CALL DIVSET(2, IV, LIV, LV, V)
+      IV1 = IV(1)
+      IF (IV1 .EQ. 12 .OR. IV1 .EQ. 13) IV(VNEED) = IV(VNEED) + 2*P + 6
+      IF (IV1 .EQ. 14) GO TO 10
+      IF (IV1 .GT. 2 .AND. IV1 .LT. 12) GO TO 10
+      G1 = 1
+      IF (IV1 .EQ. 12) IV(1) = 13
+      GO TO 20
+C
+ 10   G1 = IV(G)
+C
+ 20   CALL DRMNGB(B, D, FX, V(G1), IV, LIV, LV, P, V, X)
+      IF (IV(1) .LT. 2) GO TO 999
+      IF (IV(1) .GT. 2) GO TO 80
+C
+C  ***  COMPUTE GRADIENT  ***
+C
+      IF (IV(NITER) .EQ. 0) CALL DV7SCP(P, V(G1), ZERO)
+      J = IV(LMAT)
+      ALPHA0 = G1 - P - 1
+      IPI = IV(PERM)
+      DO 40 I = 1, P
+         K = ALPHA0 + IV(IPI)
+         V(K) = DD7TPR(I, V(J), V(J))
+         IPI = IPI + 1
+         J = J + I
+ 40      CONTINUE
+C     ***  UNDO INCREMENT OF IV(NGCALL) DONE BY DRMNGB  ***
+      IV(NGCALL) = IV(NGCALL) - 1
+C     ***  STORE RETURN CODE FROM DS3GRD IN IV(SGIRC)  ***
+      IV(SGIRC) = 0
+C     ***  X MAY HAVE BEEN RESTORED, SO COPY BACK FX... ***
+      FX = V(F)
+      GO TO 60
+C
+C     ***  GRADIENT LOOP  ***
+C
+ 50   IF (IV(TOOBIG) .NE. 0) GO TO 10
+C
+ 60   G1 = IV(G)
+      ALPHA = G1 - P
+      W = ALPHA - 6
+      CALL DS3GRD(V(ALPHA), B, D, V(ETA0), FX, V(G1), IV(SGIRC), P,
+     1            V(W), X)
+      I = IV(SGIRC)
+      IF (I .EQ. 0) GO TO 10
+      IF (I .LE. P) GO TO 70
+         IV(TOOBIG) = 1
+         GO TO 10
+C
+ 70   IV(NGCALL) = IV(NGCALL) + 1
+      GO TO 999
+C
+ 80   IF (IV(1) .NE. 14) GO TO 999
+C
+C  ***  STORAGE ALLOCATION  ***
+C
+      IV(G) = IV(NEXTV) + P + 6
+      IV(NEXTV) = IV(G) + P
+      IF (IV1 .NE. 13) GO TO 10
+C
+ 999  RETURN
+C  ***  LAST CARD OF DRMNFB FOLLOWS  ***
+      END
+      SUBROUTINE D7EGR(N,INDROW,JPNTR,INDCOL,IPNTR,NDEG,IWA,BWA)
+      INTEGER N
+      INTEGER INDROW(1),JPNTR(1),INDCOL(1),IPNTR(1),NDEG(N),IWA(N)
+      LOGICAL BWA(N)
+C     **********
+C
+C     SUBROUTINE D7EGR
+C
+C     GIVEN THE SPARSITY PATTERN OF AN M BY N MATRIX A,
+C     THIS SUBROUTINE DETERMINES THE DEGREE SEQUENCE FOR
+C     THE INTERSECTION GRAPH OF THE COLUMNS OF A.
+C
+C     IN GRAPH-THEORY TERMINOLOGY, THE INTERSECTION GRAPH OF
+C     THE COLUMNS OF A IS THE LOOPLESS GRAPH G WITH VERTICES
+C     A(J), J = 1,2,...,N WHERE A(J) IS THE J-TH COLUMN OF A
+C     AND WITH EDGE (A(I),A(J)) IF AND ONLY IF COLUMNS I AND J
+C     HAVE A NON-ZERO IN THE SAME ROW POSITION.
+C
+C     NOTE THAT THE VALUE OF M IS NOT NEEDED BY D7EGR AND IS
+C     THEREFORE NOT PRESENT IN THE SUBROUTINE STATEMENT.
+C
+C     THE SUBROUTINE STATEMENT IS
+C
+C       SUBROUTINE D7EGR(N,INDROW,JPNTR,INDCOL,IPNTR,NDEG,IWA,BWA)
+C
+C     WHERE
+C
+C       N IS A POSITIVE INTEGER INPUT VARIABLE SET TO THE NUMBER
+C         OF COLUMNS OF A.
+C
+C       INDROW IS AN INTEGER INPUT ARRAY WHICH CONTAINS THE ROW
+C         INDICES FOR THE NON-ZEROES IN THE MATRIX A.
+C
+C       JPNTR IS AN INTEGER INPUT ARRAY OF LENGTH N + 1 WHICH
+C         SPECIFIES THE LOCATIONS OF THE ROW INDICES IN INDROW.
+C         THE ROW INDICES FOR COLUMN J ARE
+C
+C               INDROW(K), K = JPNTR(J),...,JPNTR(J+1)-1.
+C
+C         NOTE THAT JPNTR(N+1)-1 IS THEN THE NUMBER OF NON-ZERO
+C         ELEMENTS OF THE MATRIX A.
+C
+C       INDCOL IS AN INTEGER INPUT ARRAY WHICH CONTAINS THE
+C         COLUMN INDICES FOR THE NON-ZEROES IN THE MATRIX A.
+C
+C       IPNTR IS AN INTEGER INPUT ARRAY OF LENGTH M + 1 WHICH
+C         SPECIFIES THE LOCATIONS OF THE COLUMN INDICES IN INDCOL.
+C         THE COLUMN INDICES FOR ROW I ARE
+C
+C               INDCOL(K), K = IPNTR(I),...,IPNTR(I+1)-1.
+C
+C         NOTE THAT IPNTR(M+1)-1 IS THEN THE NUMBER OF NON-ZERO
+C         ELEMENTS OF THE MATRIX A.
+C
+C       NDEG IS AN INTEGER OUTPUT ARRAY OF LENGTH N WHICH
+C         SPECIFIES THE DEGREE SEQUENCE. THE DEGREE OF THE
+C         J-TH COLUMN OF A IS NDEG(J).
+C
+C       IWA IS AN INTEGER WORK ARRAY OF LENGTH N.
+C
+C       BWA IS A LOGICAL WORK ARRAY OF LENGTH N.
+C
+C     ARGONNE NATIONAL LABORATORY. MINPACK PROJECT. JUNE 1982.
+C     THOMAS F. COLEMAN, BURTON S. GARBOW, JORGE J. MORE
+C
+C     **********
+      INTEGER DEG,IC,IP,IPL,IPU,IR,JCOL,JP,JPL,JPU
+C
+C     INITIALIZATION BLOCK.
+C
+      DO 10 JP = 1, N
+         NDEG(JP) = 0
+         BWA(JP) = .FALSE.
+   10    CONTINUE
+C
+C     COMPUTE THE DEGREE SEQUENCE BY DETERMINING THE CONTRIBUTIONS
+C     TO THE DEGREES FROM THE CURRENT(JCOL) COLUMN AND FURTHER
+C     COLUMNS WHICH HAVE NOT YET BEEN CONSIDERED.
+C
+      IF (N .LT. 2) GO TO 90
+      DO 80 JCOL = 2, N
+         BWA(JCOL) = .TRUE.
+         DEG = 0
+C
+C        DETERMINE ALL POSITIONS (IR,JCOL) WHICH CORRESPOND
+C        TO NON-ZEROES IN THE MATRIX.
+C
+         JPL = JPNTR(JCOL)
+         JPU = JPNTR(JCOL+1) - 1
+         IF (JPU .LT. JPL) GO TO 50
+         DO 40 JP = JPL, JPU
+            IR = INDROW(JP)
+C
+C           FOR EACH ROW IR, DETERMINE ALL POSITIONS (IR,IC)
+C           WHICH CORRESPOND TO NON-ZEROES IN THE MATRIX.
+C
+            IPL = IPNTR(IR)
+            IPU = IPNTR(IR+1) - 1
+            DO 30 IP = IPL, IPU
+               IC = INDCOL(IP)
+C
+C              ARRAY BWA MARKS COLUMNS WHICH HAVE CONTRIBUTED TO
+C              THE DEGREE COUNT OF COLUMN JCOL. UPDATE THE DEGREE
+C              COUNTS OF THESE COLUMNS. ARRAY IWA RECORDS THE
+C              MARKED COLUMNS.
+C
+               IF (BWA(IC)) GO TO 20
+               BWA(IC) = .TRUE.
+               NDEG(IC) = NDEG(IC) + 1
+               DEG = DEG + 1
+               IWA(DEG) = IC
+   20          CONTINUE
+   30          CONTINUE
+   40       CONTINUE
+   50    CONTINUE
+C
+C        UN-MARK THE COLUMNS RECORDED BY IWA AND FINALIZE THE
+C        DEGREE COUNT OF COLUMN JCOL.
+C
+         IF (DEG .LT. 1) GO TO 70
+         DO 60 JP = 1, DEG
+            IC = IWA(JP)
+            BWA(IC) = .FALSE.
+   60       CONTINUE
+         NDEG(JCOL) = NDEG(JCOL) + DEG
+   70    CONTINUE
+   80    CONTINUE
+   90 CONTINUE
+      RETURN
+C
+C     LAST CARD OF SUBROUTINE D7EGR.
+C
+      END
+      SUBROUTINE DRMNG(D, FX, G, IV, LIV, LV, N, V, X)
+C
+C  ***  CARRY OUT  DMNG (UNCONSTRAINED MINIMIZATION) ITERATIONS, USING
+C  ***  DOUBLE-DOGLEG/BFGS STEPS.
+C
+C  ***  PARAMETER DECLARATIONS  ***
+C
+      INTEGER LIV, LV, N
+      INTEGER IV(LIV)
+      DOUBLE PRECISION D(N), FX, G(N), V(LV), X(N)
+C
+C--------------------------  PARAMETER USAGE  --------------------------
+C
+C D.... SCALE VECTOR.
+C FX... FUNCTION VALUE.
+C G.... GRADIENT VECTOR.
+C IV... INTEGER VALUE ARRAY.
+C LIV.. LENGTH OF IV (AT LEAST 60).
+C LV... LENGTH OF V (AT LEAST 71 + N*(N+13)/2).
+C N.... NUMBER OF VARIABLES (COMPONENTS IN X AND G).
+C V.... FLOATING-POINT VALUE ARRAY.
+C X.... VECTOR OF PARAMETERS TO BE OPTIMIZED.
+C
+C  ***  DISCUSSION  ***
+C
+C        PARAMETERS IV, N, V, AND X ARE THE SAME AS THE CORRESPONDING
+C     ONES TO  DMNG (WHICH SEE), EXCEPT THAT V CAN BE SHORTER (SINCE
+C     THE PART OF V THAT  DMNG USES FOR STORING G IS NOT NEEDED).
+C     MOREOVER, COMPARED WITH  DMNG, IV(1) MAY HAVE THE TWO ADDITIONAL
+C     OUTPUT VALUES 1 AND 2, WHICH ARE EXPLAINED BELOW, AS IS THE USE
+C     OF IV(TOOBIG) AND IV(NFGCAL).  THE VALUE IV(G), WHICH IS AN
+C     OUTPUT VALUE FROM  DMNG (AND  DMNF), IS NOT REFERENCED BY
+C     DRMNG OR THE SUBROUTINES IT CALLS.
+C        FX AND G NEED NOT HAVE BEEN INITIALIZED WHEN DRMNG IS CALLED
+C     WITH IV(1) = 12, 13, OR 14.
+C
+C IV(1) = 1 MEANS THE CALLER SHOULD SET FX TO F(X), THE FUNCTION VALUE
+C             AT X, AND CALL DRMNG AGAIN, HAVING CHANGED NONE OF THE
+C             OTHER PARAMETERS.  AN EXCEPTION OCCURS IF F(X) CANNOT BE
+C             (E.G. IF OVERFLOW WOULD OCCUR), WHICH MAY HAPPEN BECAUSE
+C             OF AN OVERSIZED STEP.  IN THIS CASE THE CALLER SHOULD SET
+C             IV(TOOBIG) = IV(2) TO 1, WHICH WILL CAUSE DRMNG TO IG-
+C             NORE FX AND TRY A SMALLER STEP.  THE PARAMETER NF THAT
+C              DMNG PASSES TO CALCF (FOR POSSIBLE USE BY CALCG) IS A
+C             COPY OF IV(NFCALL) = IV(6).
+C IV(1) = 2 MEANS THE CALLER SHOULD SET G TO G(X), THE GRADIENT VECTOR
+C             OF F AT X, AND CALL DRMNG AGAIN, HAVING CHANGED NONE OF
+C             THE OTHER PARAMETERS EXCEPT POSSIBLY THE SCALE VECTOR D
+C             WHEN IV(DTYPE) = 0.  THE PARAMETER NF THAT  DMNG PASSES
+C             TO CALCG IS IV(NFGCAL) = IV(7).  IF G(X) CANNOT BE
+C             EVALUATED, THEN THE CALLER MAY SET IV(TOOBIG) TO 0, IN
+C             WHICH CASE DRMNG WILL RETURN WITH IV(1) = 65.
+C.
+C  ***  GENERAL  ***
+C
+C     CODED BY DAVID M. GAY (DECEMBER 1979).  REVISED SEPT. 1982.
+C     THIS SUBROUTINE WAS WRITTEN IN CONNECTION WITH RESEARCH SUPPORTED
+C     IN PART BY THE NATIONAL SCIENCE FOUNDATION UNDER GRANTS
+C     MCS-7600324 AND MCS-7906671.
+C
+C        (SEE  DMNG FOR REFERENCES.)
+C
+C+++++++++++++++++++++++++++  DECLARATIONS  ++++++++++++++++++++++++++++
+C
+C  ***  LOCAL VARIABLES  ***
+C
+      INTEGER DG1, DUMMY, G01, I, K, L, LSTGST, NWTST1, RSTRST, STEP1,
+     1        TEMP1, W, X01, Z
+      DOUBLE PRECISION T
+C
+C     ***  CONSTANTS  ***
+C
+      DOUBLE PRECISION HALF, NEGONE, ONE, ONEP2, ZERO
+C
+C  ***  NO INTRINSIC FUNCTIONS  ***
+C
+C  ***  EXTERNAL FUNCTIONS AND SUBROUTINES  ***
+C
+      LOGICAL STOPX
+      DOUBLE PRECISION DD7TPR, DRLDST, DV2NRM
+      EXTERNAL DA7SST,DD7DOG,DIVSET, DD7TPR,DITSUM, DL7ITV, DL7IVM,
+     1         DL7TVM, DL7UPD,DL7VML,DPARCK, DRLDST, STOPX,DV2AXY,
+     2        DV7CPY, DV7SCP, DV7VMP, DV2NRM, DW7ZBF
+C
+C DA7SST.... ASSESSES CANDIDATE STEP.
+C DD7DOG.... COMPUTES DOUBLE-DOGLEG (CANDIDATE) STEP.
+C DIVSET.... SUPPLIES DEFAULT IV AND V INPUT COMPONENTS.
+C DD7TPR... RETURNS INNER PRODUCT OF TWO VECTORS.
+C DITSUM.... PRINTS ITERATION SUMMARY AND INFO ON INITIAL AND FINAL X.
+C DL7ITV... MULTIPLIES INVERSE TRANSPOSE OF LOWER TRIANGLE TIMES VECTOR.
+C DL7IVM... MULTIPLIES INVERSE OF LOWER TRIANGLE TIMES VECTOR.
+C DL7TVM... MULTIPLIES TRANSPOSE OF LOWER TRIANGLE TIMES VECTOR.
+C LUPDT.... UPDATES CHOLESKY FACTOR OF HESSIAN APPROXIMATION.
+C DL7VML.... MULTIPLIES LOWER TRIANGLE TIMES VECTOR.
+C DPARCK.... CHECKS VALIDITY OF INPUT IV AND V VALUES.
+C DRLDST... COMPUTES V(RELDX) = RELATIVE STEP SIZE.
+C STOPX.... RETURNS .TRUE. IF THE BREAK KEY HAS BEEN PRESSED.
+C DV2AXY.... COMPUTES SCALAR TIMES ONE VECTOR PLUS ANOTHER.
+C DV7CPY.... COPIES ONE VECTOR TO ANOTHER.
+C DV7SCP... SETS ALL ELEMENTS OF A VECTOR TO A SCALAR.
+C DV7VMP... MULTIPLIES VECTOR BY VECTOR RAISED TO POWER (COMPONENTWISE).
+C DV2NRM... RETURNS THE 2-NORM OF A VECTOR.
+C DW7ZBF... COMPUTES W AND Z FOR DL7UPD CORRESPONDING TO BFGS UPDATE.
+C
+C  ***  SUBSCRIPTS FOR IV AND V  ***
+C
+      INTEGER CNVCOD, DG, DGNORM, DINIT, DSTNRM, DST0, F, F0, FDIF,
+     1        GTHG, GTSTEP, G0, INCFAC, INITH, IRC, KAGQT, LMAT, LMAX0,
+     2        LMAXS, MODE, MODEL, MXFCAL, MXITER, NEXTV, NFCALL, NFGCAL,
+     3        NGCALL, NITER, NREDUC, NWTSTP, PREDUC, RADFAC, RADINC,
+     4        RADIUS, RAD0, RELDX, RESTOR, STEP, STGLIM, STLSTG, TOOBIG,
+     5        TUNER4, TUNER5, VNEED, XIRC, X0
+C
+C  ***  IV SUBSCRIPT VALUES  ***
+C
+      PARAMETER (CNVCOD=55, DG=37, G0=48, INITH=25, IRC=29, KAGQT=33,
+     1           MODE=35, MODEL=5, MXFCAL=17, MXITER=18, NFCALL=6,
+     2           NFGCAL=7, NGCALL=30, NITER=31, NWTSTP=34, RADINC=8,
+     3           RESTOR=9, STEP=40, STGLIM=11, STLSTG=41, TOOBIG=2,
+     4           VNEED=4, XIRC=13, X0=43)
+C
+C  ***  V SUBSCRIPT VALUES  ***
+C
+      PARAMETER (DGNORM=1, DINIT=38, DSTNRM=2, DST0=3, F=10, F0=13,
+     1           FDIF=11, GTHG=44, GTSTEP=4, INCFAC=23, LMAT=42,
+     2           LMAX0=35, LMAXS=36, NEXTV=47, NREDUC=6, PREDUC=7,
+     3           RADFAC=16, RADIUS=8, RAD0=9, RELDX=17, TUNER4=29,
+     4           TUNER5=30)
+C
+      PARAMETER (HALF=0.5D+0, NEGONE=-1.D+0, ONE=1.D+0, ONEP2=1.2D+0,
+     1           ZERO=0.D+0)
+C
+C+++++++++++++++++++++++++++++++  BODY  ++++++++++++++++++++++++++++++++
+C
+      I = IV(1)
+      IF (I .EQ. 1) GO TO 50
+      IF (I .EQ. 2) GO TO 60
+C
+C  ***  CHECK VALIDITY OF IV AND V INPUT VALUES  ***
+C
+      IF (IV(1) .EQ. 0) CALL DIVSET(2, IV, LIV, LV, V)
+      IF (IV(1) .EQ. 12 .OR. IV(1) .EQ. 13)
+     1     IV(VNEED) = IV(VNEED) + N*(N+13)/2
+      CALL DPARCK(2, D, IV, LIV, LV, N, V)
+      I = IV(1) - 2
+      IF (I .GT. 12) GO TO 999
+      GO TO (190, 190, 190, 190, 190, 190, 120, 90, 120, 10, 10, 20), I
+C
+C  ***  STORAGE ALLOCATION  ***
+C
+ 10   L = IV(LMAT)
+      IV(X0) = L + N*(N+1)/2
+      IV(STEP) = IV(X0) + N
+      IV(STLSTG) = IV(STEP) + N
+      IV(G0) = IV(STLSTG) + N
+      IV(NWTSTP) = IV(G0) + N
+      IV(DG) = IV(NWTSTP) + N
+      IV(NEXTV) = IV(DG) + N
+      IF (IV(1) .NE. 13) GO TO 20
+         IV(1) = 14
+         GO TO 999
+C
+C  ***  INITIALIZATION  ***
+C
+ 20   IV(NITER) = 0
+      IV(NFCALL) = 1
+      IV(NGCALL) = 1
+      IV(NFGCAL) = 1
+      IV(MODE) = -1
+      IV(MODEL) = 1
+      IV(STGLIM) = 1
+      IV(TOOBIG) = 0
+      IV(CNVCOD) = 0
+      IV(RADINC) = 0
+      V(RAD0) = ZERO
+      IF (V(DINIT) .GE. ZERO) CALL DV7SCP(N, D, V(DINIT))
+      IF (IV(INITH) .NE. 1) GO TO 40
+C
+C     ***  SET THE INITIAL HESSIAN APPROXIMATION TO DIAG(D)**-2  ***
+C
+         L = IV(LMAT)
+         CALL DV7SCP(N*(N+1)/2, V(L), ZERO)
+         K = L - 1
+         DO 30 I = 1, N
+              K = K + I
+              T = D(I)
+              IF (T .LE. ZERO) T = ONE
+              V(K) = T
+ 30           CONTINUE
+C
+C  ***  COMPUTE INITIAL FUNCTION VALUE  ***
+C
+ 40   IV(1) = 1
+      GO TO 999
+C
+ 50   V(F) = FX
+      IF (IV(MODE) .GE. 0) GO TO 190
+      V(F0) = FX
+      IV(1) = 2
+      IF (IV(TOOBIG) .EQ. 0) GO TO 999
+         IV(1) = 63
+         GO TO 350
+C
+C  ***  MAKE SURE GRADIENT COULD BE COMPUTED  ***
+C
+ 60   IF (IV(TOOBIG) .EQ. 0) GO TO 70
+         IV(1) = 65
+         GO TO 350
+C
+ 70   DG1 = IV(DG)
+      CALL DV7VMP(N, V(DG1), G, D, -1)
+      V(DGNORM) = DV2NRM(N, V(DG1))
+C
+      IF (IV(CNVCOD) .NE. 0) GO TO 340
+      IF (IV(MODE) .EQ. 0) GO TO 300
+C
+C  ***  ALLOW FIRST STEP TO HAVE SCALED 2-NORM AT MOST V(LMAX0)  ***
+C
+      V(RADIUS) = V(LMAX0)
+C
+      IV(MODE) = 0
+C
+C
+C-----------------------------  MAIN LOOP  -----------------------------
+C
+C
+C  ***  PRINT ITERATION SUMMARY, CHECK ITERATION LIMIT  ***
+C
+ 80   CALL DITSUM(D, G, IV, LIV, LV, N, V, X)
+ 90   K = IV(NITER)
+      IF (K .LT. IV(MXITER)) GO TO 100
+         IV(1) = 10
+         GO TO 350
+C
+C  ***  UPDATE RADIUS  ***
+C
+ 100  IV(NITER) = K + 1
+      IF (K .GT. 0) V(RADIUS) = V(RADFAC) * V(DSTNRM)
+C
+C  ***  INITIALIZE FOR START OF NEXT ITERATION  ***
+C
+      G01 = IV(G0)
+      X01 = IV(X0)
+      V(F0) = V(F)
+      IV(IRC) = 4
+      IV(KAGQT) = -1
+C
+C     ***  COPY X TO X0, G TO G0  ***
+C
+      CALL DV7CPY(N, V(X01), X)
+      CALL DV7CPY(N, V(G01), G)
+C
+C  ***  CHECK STOPX AND FUNCTION EVALUATION LIMIT  ***
+C
+ 110  IF (.NOT. STOPX(DUMMY)) GO TO 130
+         IV(1) = 11
+         GO TO 140
+C
+C     ***  COME HERE WHEN RESTARTING AFTER FUNC. EVAL. LIMIT OR STOPX.
+C
+ 120  IF (V(F) .GE. V(F0)) GO TO 130
+         V(RADFAC) = ONE
+         K = IV(NITER)
+         GO TO 100
+C
+ 130  IF (IV(NFCALL) .LT. IV(MXFCAL)) GO TO 150
+         IV(1) = 9
+ 140     IF (V(F) .GE. V(F0)) GO TO 350
+C
+C        ***  IN CASE OF STOPX OR FUNCTION EVALUATION LIMIT WITH
+C        ***  IMPROVED V(F), EVALUATE THE GRADIENT AT X.
+C
+              IV(CNVCOD) = IV(1)
+              GO TO 290
+C
+C. . . . . . . . . . . . .  COMPUTE CANDIDATE STEP  . . . . . . . . . .
+C
+ 150  STEP1 = IV(STEP)
+      DG1 = IV(DG)
+      NWTST1 = IV(NWTSTP)
+      IF (IV(KAGQT) .GE. 0) GO TO 160
+         L = IV(LMAT)
+         CALL DL7IVM(N, V(NWTST1), V(L), G)
+         V(NREDUC) = HALF * DD7TPR(N, V(NWTST1), V(NWTST1))
+         CALL DL7ITV(N, V(NWTST1), V(L), V(NWTST1))
+         CALL DV7VMP(N, V(STEP1), V(NWTST1), D, 1)
+         V(DST0) = DV2NRM(N, V(STEP1))
+         CALL DV7VMP(N, V(DG1), V(DG1), D, -1)
+         CALL DL7TVM(N, V(STEP1), V(L), V(DG1))
+         V(GTHG) = DV2NRM(N, V(STEP1))
+         IV(KAGQT) = 0
+ 160  CALL DD7DOG(V(DG1), LV, N, V(NWTST1), V(STEP1), V)
+      IF (IV(IRC) .NE. 6) GO TO 170
+         IF (IV(RESTOR) .NE. 2) GO TO 190
+         RSTRST = 2
+         GO TO 200
+C
+C  ***  CHECK WHETHER EVALUATING F(X0 + STEP) LOOKS WORTHWHILE  ***
+C
+ 170  IV(TOOBIG) = 0
+      IF (V(DSTNRM) .LE. ZERO) GO TO 190
+      IF (IV(IRC) .NE. 5) GO TO 180
+      IF (V(RADFAC) .LE. ONE) GO TO 180
+      IF (V(PREDUC) .GT. ONEP2 * V(FDIF)) GO TO 180
+         IF (IV(RESTOR) .NE. 2) GO TO 190
+         RSTRST = 0
+         GO TO 200
+C
+C  ***  COMPUTE F(X0 + STEP)  ***
+C
+ 180  X01 = IV(X0)
+      STEP1 = IV(STEP)
+      CALL DV2AXY(N, X, ONE, V(STEP1), V(X01))
+      IV(NFCALL) = IV(NFCALL) + 1
+      IV(1) = 1
+      GO TO 999
+C
+C. . . . . . . . . . . . .  ASSESS CANDIDATE STEP  . . . . . . . . . . .
+C
+ 190  RSTRST = 3
+ 200  X01 = IV(X0)
+      V(RELDX) = DRLDST(N, D, X, V(X01))
+      CALL DA7SST(IV, LIV, LV, V)
+      STEP1 = IV(STEP)
+      LSTGST = IV(STLSTG)
+      I = IV(RESTOR) + 1
+      GO TO (240, 210, 220, 230), I
+ 210  CALL DV7CPY(N, X, V(X01))
+      GO TO 240
+ 220   CALL DV7CPY(N, V(LSTGST), V(STEP1))
+       GO TO 240
+ 230     CALL DV7CPY(N, V(STEP1), V(LSTGST))
+         CALL DV2AXY(N, X, ONE, V(STEP1), V(X01))
+         V(RELDX) = DRLDST(N, D, X, V(X01))
+         IV(RESTOR) = RSTRST
+C
+ 240  K = IV(IRC)
+      GO TO (250,280,280,280,250,260,270,270,270,270,270,270,330,300), K
+C
+C     ***  RECOMPUTE STEP WITH CHANGED RADIUS  ***
+C
+ 250     V(RADIUS) = V(RADFAC) * V(DSTNRM)
+         GO TO 110
+C
+C  ***  COMPUTE STEP OF LENGTH V(LMAXS) FOR SINGULAR CONVERGENCE TEST.
+C
+ 260  V(RADIUS) = V(LMAXS)
+      GO TO 150
+C
+C  ***  CONVERGENCE OR FALSE CONVERGENCE  ***
+C
+ 270  IV(CNVCOD) = K - 4
+      IF (V(F) .GE. V(F0)) GO TO 340
+         IF (IV(XIRC) .EQ. 14) GO TO 340
+              IV(XIRC) = 14
+C
+C. . . . . . . . . . . .  PROCESS ACCEPTABLE STEP  . . . . . . . . . . .
+C
+ 280  IF (IV(IRC) .NE. 3) GO TO 290
+         STEP1 = IV(STEP)
+         TEMP1 = IV(STLSTG)
+C
+C     ***  SET  TEMP1 = HESSIAN * STEP  FOR USE IN GRADIENT TESTS  ***
+C
+         L = IV(LMAT)
+         CALL DL7TVM(N, V(TEMP1), V(L), V(STEP1))
+         CALL DL7VML(N, V(TEMP1), V(L), V(TEMP1))
+C
+C  ***  COMPUTE GRADIENT  ***
+C
+ 290  IV(NGCALL) = IV(NGCALL) + 1
+      IV(1) = 2
+      GO TO 999
+C
+C  ***  INITIALIZATIONS -- G0 = G - G0, ETC.  ***
+C
+ 300  G01 = IV(G0)
+      CALL DV2AXY(N, V(G01), NEGONE, V(G01), G)
+      STEP1 = IV(STEP)
+      TEMP1 = IV(STLSTG)
+      IF (IV(IRC) .NE. 3) GO TO 320
+C
+C  ***  SET V(RADFAC) BY GRADIENT TESTS  ***
+C
+C     ***  SET  TEMP1 = DIAG(D)**-1 * (HESSIAN*STEP + (G(X0)-G(X)))  ***
+C
+         CALL DV2AXY(N, V(TEMP1), NEGONE, V(G01), V(TEMP1))
+         CALL DV7VMP(N, V(TEMP1), V(TEMP1), D, -1)
+C
+C        ***  DO GRADIENT TESTS  ***
+C
+         IF (DV2NRM(N, V(TEMP1)) .LE. V(DGNORM) * V(TUNER4))
+     1                  GO TO 310
+              IF (DD7TPR(N, G, V(STEP1))
+     1                  .GE. V(GTSTEP) * V(TUNER5))  GO TO 320
+ 310               V(RADFAC) = V(INCFAC)
+C
+C  ***  UPDATE H, LOOP  ***
+C
+ 320  W = IV(NWTSTP)
+      Z = IV(X0)
+      L = IV(LMAT)
+      CALL DW7ZBF(V(L), N, V(STEP1), V(W), V(G01), V(Z))
+C
+C     ** USE THE N-VECTORS STARTING AT V(STEP1) AND V(G01) FOR SCRATCH..
+      CALL DL7UPD(V(TEMP1), V(STEP1), V(L), V(G01), V(L), N, V(W), V(Z))
+      IV(1) = 2
+      GO TO 80
+C
+C. . . . . . . . . . . . . .  MISC. DETAILS  . . . . . . . . . . . . . .
+C
+C  ***  BAD PARAMETERS TO ASSESS  ***
+C
+ 330  IV(1) = 64
+      GO TO 350
+C
+C  ***  PRINT SUMMARY OF FINAL ITERATION AND OTHER REQUESTED ITEMS  ***
+C
+ 340  IV(1) = IV(CNVCOD)
+      IV(CNVCOD) = 0
+ 350  CALL DITSUM(D, G, IV, LIV, LV, N, V, X)
+C
+ 999  RETURN
+C
+C  ***  LAST LINE OF DRMNG FOLLOWS  ***
+      END
+      SUBROUTINE I7DO(M,N,INDROW,JPNTR,INDCOL,IPNTR,NDEG,LIST,
+     *               MAXCLQ,IWA1,IWA2,IWA3,IWA4,BWA)
+      INTEGER M,N,MAXCLQ
+      INTEGER INDROW(1),JPNTR(1),INDCOL(1),IPNTR(1),NDEG(N),LIST(N),
+     *        IWA1(N),IWA2(N),IWA3(N),IWA4(N)
+      LOGICAL BWA(N)
+C     **********
+C
+C     SUBROUTINE I7DO
+C
+C     GIVEN THE SPARSITY PATTERN OF AN M BY N MATRIX A, THIS
+C     SUBROUTINE DETERMINES AN INCIDENCE-DEGREE ORDERING OF THE
+C     COLUMNS OF A.
+C
+C     THE INCIDENCE-DEGREE ORDERING IS DEFINED FOR THE LOOPLESS
+C     GRAPH G WITH VERTICES A(J), J = 1,2,...,N WHERE A(J) IS THE
+C     J-TH COLUMN OF A AND WITH EDGE (A(I),A(J)) IF AND ONLY IF
+C     COLUMNS I AND J HAVE A NON-ZERO IN THE SAME ROW POSITION.
+C
+C     AT EACH STAGE OF I7DO, A COLUMN OF MAXIMAL INCIDENCE IS
+C     CHOSEN AND ORDERED. IF JCOL IS AN UN-ORDERED COLUMN, THEN
+C     THE INCIDENCE OF JCOL IS THE NUMBER OF ORDERED COLUMNS
+C     ADJACENT TO JCOL IN THE GRAPH G. AMONG ALL THE COLUMNS OF
+C     MAXIMAL INCIDENCE,I7DO CHOOSES A COLUMN OF MAXIMAL DEGREE.
+C
+C     THE SUBROUTINE STATEMENT IS
+C
+C       SUBROUTINE I7DO(M,N,INDROW,JPNTR,INDCOL,IPNTR,NDEG,LIST,
+C                      MAXCLQ,IWA1,IWA2,IWA3,IWA4,BWA)
+C
+C     WHERE
+C
+C       M IS A POSITIVE INTEGER INPUT VARIABLE SET TO THE NUMBER
+C         OF ROWS OF A.
+C
+C       N IS A POSITIVE INTEGER INPUT VARIABLE SET TO THE NUMBER
+C         OF COLUMNS OF A.
+C
+C       INDROW IS AN INTEGER INPUT ARRAY WHICH CONTAINS THE ROW
+C         INDICES FOR THE NON-ZEROES IN THE MATRIX A.
+C
+C       JPNTR IS AN INTEGER INPUT ARRAY OF LENGTH N + 1 WHICH
+C         SPECIFIES THE LOCATIONS OF THE ROW INDICES IN INDROW.
+C         THE ROW INDICES FOR COLUMN J ARE
+C
+C               INDROW(K), K = JPNTR(J),...,JPNTR(J+1)-1.
+C
+C         NOTE THAT JPNTR(N+1)-1 IS THEN THE NUMBER OF NON-ZERO
+C         ELEMENTS OF THE MATRIX A.
+C
+C       INDCOL IS AN INTEGER INPUT ARRAY WHICH CONTAINS THE
+C         COLUMN INDICES FOR THE NON-ZEROES IN THE MATRIX A.
+C
+C       IPNTR IS AN INTEGER INPUT ARRAY OF LENGTH M + 1 WHICH
+C         SPECIFIES THE LOCATIONS OF THE COLUMN INDICES IN INDCOL.
+C         THE COLUMN INDICES FOR ROW I ARE
+C
+C               INDCOL(K), K = IPNTR(I),...,IPNTR(I+1)-1.
+C
+C         NOTE THAT IPNTR(M+1)-1 IS THEN THE NUMBER OF NON-ZERO
+C         ELEMENTS OF THE MATRIX A.
+C
+C       NDEG IS AN INTEGER INPUT ARRAY OF LENGTH N WHICH SPECIFIES
+C         THE DEGREE SEQUENCE. THE DEGREE OF THE J-TH COLUMN
+C         OF A IS NDEG(J).
+C
+C       LIST IS AN INTEGER OUTPUT ARRAY OF LENGTH N WHICH SPECIFIES
+C         THE INCIDENCE-DEGREE ORDERING OF THE COLUMNS OF A. THE J-TH
+C         COLUMN IN THIS ORDER IS LIST(J).
+C
+C       MAXCLQ IS AN INTEGER OUTPUT VARIABLE SET TO THE SIZE
+C         OF THE LARGEST CLIQUE FOUND DURING THE ORDERING.
+C
+C       IWA1,IWA2,IWA3, AND IWA4 ARE INTEGER WORK ARRAYS OF LENGTH N.
+C
+C       BWA IS A LOGICAL WORK ARRAY OF LENGTH N.
+C
+C     SUBPROGRAMS CALLED
+C
+C       MINPACK-SUPPLIED ... N7MSRT
+C
+C       FORTRAN-SUPPLIED ... MAX0
+C
+C     ARGONNE NATIONAL LABORATORY. MINPACK PROJECT. JUNE 1982.
+C     THOMAS F. COLEMAN, BURTON S. GARBOW, JORGE J. MORE
+C
+C     **********
+      INTEGER DEG,HEAD,IC,IP,IPL,IPU,IR,JCOL,JP,JPL,JPU,L,MAXINC,
+     *        MAXLST,NCOMP,NUMINC,NUMLST,NUMORD,NUMWGT
+C
+C     SORT THE DEGREE SEQUENCE.
+C
+      CALL N7MSRT(N,N-1,NDEG,-1,IWA4,IWA1,IWA3)
+C
+C     INITIALIZATION BLOCK.
+C
+C     CREATE A DOUBLY-LINKED LIST TO ACCESS THE INCIDENCES OF THE
+C     COLUMNS. THE POINTERS FOR THE LINKED LIST ARE AS FOLLOWS.
+C
+C     EACH UN-ORDERED COLUMN JCOL IS IN A LIST (THE INCIDENCE LIST)
+C     OF COLUMNS WITH THE SAME INCIDENCE.
+C
+C     IWA1(NUMINC+1) IS THE FIRST COLUMN IN THE NUMINC LIST
+C     UNLESS IWA1(NUMINC+1) = 0. IN THIS CASE THERE ARE
+C     NO COLUMNS IN THE NUMINC LIST.
+C
+C     IWA2(JCOL) IS THE COLUMN BEFORE JCOL IN THE INCIDENCE LIST
+C     UNLESS IWA2(JCOL) = 0. IN THIS CASE JCOL IS THE FIRST
+C     COLUMN IN THIS INCIDENCE LIST.
+C
+C     IWA3(JCOL) IS THE COLUMN AFTER JCOL IN THE INCIDENCE LIST
+C     UNLESS IWA3(JCOL) = 0. IN THIS CASE JCOL IS THE LAST
+C     COLUMN IN THIS INCIDENCE LIST.
+C
+C     IF JCOL IS AN UN-ORDERED COLUMN, THEN LIST(JCOL) IS THE
+C     INCIDENCE OF JCOL IN THE GRAPH. IF JCOL IS AN ORDERED COLUMN,
+C     THEN LIST(JCOL) IS THE INCIDENCE-DEGREE ORDER OF COLUMN JCOL.
+C
+      MAXINC = 0
+      DO 10 JP = 1, N
+         LIST(JP) = 0
+         BWA(JP) = .FALSE.
+         IWA1(JP) = 0
+         L = IWA4(JP)
+         IF (JP .NE. 1) IWA2(L) = IWA4(JP-1)
+         IF (JP .NE. N) IWA3(L) = IWA4(JP+1)
+   10    CONTINUE
+      IWA1(1) = IWA4(1)
+      L = IWA4(1)
+      IWA2(L) = 0
+      L = IWA4(N)
+      IWA3(L) = 0
+C
+C     DETERMINE THE MAXIMAL SEARCH LENGTH FOR THE LIST
+C     OF COLUMNS OF MAXIMAL INCIDENCE.
+C
+      MAXLST = 0
+      DO 20 IR = 1, M
+         MAXLST = MAXLST + (IPNTR(IR+1) - IPNTR(IR))**2
+   20    CONTINUE
+      MAXLST = MAXLST/N
+      MAXCLQ = 1
+C
+C     BEGINNING OF ITERATION LOOP.
+C
+      DO 140 NUMORD = 1, N
+C
+C        CHOOSE A COLUMN JCOL OF MAXIMAL DEGREE AMONG THE
+C        COLUMNS OF MAXIMAL INCIDENCE.
+C
+         JP = IWA1(MAXINC+1)
+         NUMLST = 1
+         NUMWGT = -1
+   30    CONTINUE
+            IF (NDEG(JP) .LE. NUMWGT) GO TO 40
+            NUMWGT = NDEG(JP)
+            JCOL = JP
+   40       CONTINUE
+            JP = IWA3(JP)
+            NUMLST = NUMLST + 1
+            IF (JP .GT. 0 .AND. NUMLST .LE. MAXLST) GO TO 30
+         LIST(JCOL) = NUMORD
+C
+C        DELETE COLUMN JCOL FROM THE LIST OF COLUMNS OF
+C        MAXIMAL INCIDENCE.
+C
+         L = IWA2(JCOL)
+         IF (L .EQ. 0) IWA1(MAXINC+1) = IWA3(JCOL)
+         IF (L .GT. 0) IWA3(L) = IWA3(JCOL)
+         L = IWA3(JCOL)
+         IF (L .GT. 0) IWA2(L) = IWA2(JCOL)
+C
+C        UPDATE THE SIZE OF THE LARGEST CLIQUE
+C        FOUND DURING THE ORDERING.
+C
+         IF (MAXINC .EQ. 0) NCOMP = 0
+         NCOMP = NCOMP + 1
+         IF (MAXINC + 1 .EQ. NCOMP) MAXCLQ = MAX0(MAXCLQ,NCOMP)
+C
+C        UPDATE THE MAXIMAL INCIDENCE COUNT.
+C
+   50    CONTINUE
+            IF (IWA1(MAXINC+1) .GT. 0) GO TO 60
+            MAXINC = MAXINC - 1
+            IF (MAXINC .GE. 0) GO TO 50
+   60    CONTINUE
+C
+C        FIND ALL COLUMNS ADJACENT TO COLUMN JCOL.
+C
+         BWA(JCOL) = .TRUE.
+         DEG = 0
+C
+C        DETERMINE ALL POSITIONS (IR,JCOL) WHICH CORRESPOND
+C        TO NON-ZEROES IN THE MATRIX.
+C
+         JPL = JPNTR(JCOL)
+         JPU = JPNTR(JCOL+1) - 1
+         IF (JPU .LT. JPL) GO TO 100
+         DO 90 JP = JPL, JPU
+            IR = INDROW(JP)
+C
+C           FOR EACH ROW IR, DETERMINE ALL POSITIONS (IR,IC)
+C           WHICH CORRESPOND TO NON-ZEROES IN THE MATRIX.
+C
+            IPL = IPNTR(IR)
+            IPU = IPNTR(IR+1) - 1
+            DO 80 IP = IPL, IPU
+               IC = INDCOL(IP)
+C
+C              ARRAY BWA MARKS COLUMNS WHICH ARE ADJACENT TO
+C              COLUMN JCOL. ARRAY IWA4 RECORDS THE MARKED COLUMNS.
+C
+               IF (BWA(IC)) GO TO 70
+               BWA(IC) = .TRUE.
+               DEG = DEG + 1
+               IWA4(DEG) = IC
+   70          CONTINUE
+   80          CONTINUE
+   90       CONTINUE
+  100    CONTINUE
+C
+C        UPDATE THE POINTERS TO THE INCIDENCE LISTS.
+C
+         IF (DEG .LT. 1) GO TO 130
+         DO 120 JP = 1, DEG
+            IC = IWA4(JP)
+            IF (LIST(IC) .GT. 0) GO TO 110
+            NUMINC = -LIST(IC) + 1
+            LIST(IC) = -NUMINC
+            MAXINC = MAX0(MAXINC,NUMINC)
+C
+C           DELETE COLUMN IC FROM THE NUMINC-1 LIST.
+C
+            L = IWA2(IC)
+            IF (L .EQ. 0) IWA1(NUMINC) = IWA3(IC)
+            IF (L .GT. 0) IWA3(L) = IWA3(IC)
+            L = IWA3(IC)
+            IF (L .GT. 0) IWA2(L) = IWA2(IC)
+C
+C           ADD COLUMN IC TO THE NUMINC LIST.
+C
+            HEAD = IWA1(NUMINC+1)
+            IWA1(NUMINC+1) = IC
+            IWA2(IC) = 0
+            IWA3(IC) = HEAD
+            IF (HEAD .GT. 0) IWA2(HEAD) = IC
+  110       CONTINUE
+C
+C           UN-MARK COLUMN IC IN THE ARRAY BWA.
+C
+            BWA(IC) = .FALSE.
+  120       CONTINUE
+  130    CONTINUE
+         BWA(JCOL) = .FALSE.
+C
+C        END OF ITERATION LOOP.
+C
+  140    CONTINUE
+C
+C     INVERT THE ARRAY LIST.
+C
+      DO 150 JCOL = 1, N
+         NUMORD = LIST(JCOL)
+         IWA1(NUMORD) = JCOL
+  150    CONTINUE
+      DO 160 JP = 1, N
+         LIST(JP) = IWA1(JP)
+  160    CONTINUE
+      RETURN
+C
+C     LAST CARD OF SUBROUTINE I7DO.
+C
+      END
+      SUBROUTINE M7SLO(N,INDROW,JPNTR,INDCOL,IPNTR,NDEG,LIST,
+     *               MAXCLQ,IWA1,IWA2,IWA3,IWA4,BWA)
+      INTEGER N,MAXCLQ
+      INTEGER INDROW(1),JPNTR(1),INDCOL(1),IPNTR(1),NDEG(N),
+     *        LIST(N),IWA1(N),IWA2(N),IWA3(N),IWA4(N)
+      LOGICAL BWA(N)
+C     **********
+C
+C     SUBROUTINE M7SLO
+C
+C     GIVEN THE SPARSITY PATTERN OF AN M BY N MATRIX A, THIS
+C     SUBROUTINE DETERMINES THE SMALLEST-LAST ORDERING OF THE
+C     COLUMNS OF A.
+C
+C     THE SMALLEST-LAST ORDERING IS DEFINED FOR THE LOOPLESS
+C     GRAPH G WITH VERTICES A(J), J = 1,2,...,N WHERE A(J) IS THE
+C     J-TH COLUMN OF A AND WITH EDGE (A(I),A(J)) IF AND ONLY IF
+C     COLUMNS I AND J HAVE A NON-ZERO IN THE SAME ROW POSITION.
+C
+C     THE SMALLEST-LAST ORDERING IS DETERMINED RECURSIVELY BY
+C     LETTING LIST(K), K = N,...,1 BE A COLUMN WITH LEAST DEGREE
+C     IN THE SUBGRAPH SPANNED BY THE UN-ORDERED COLUMNS.
+C
+C     NOTE THAT THE VALUE OF M IS NOT NEEDED BY M7SLO AND IS
+C     THEREFORE NOT PRESENT IN THE SUBROUTINE STATEMENT.
+C
+C     THE SUBROUTINE STATEMENT IS
+C
+C       SUBROUTINE M7SLO(N,INDROW,JPNTR,INDCOL,IPNTR,NDEG,LIST,
+C                      MAXCLQ,IWA1,IWA2,IWA3,IWA4,BWA)
+C
+C     WHERE
+C
+C       N IS A POSITIVE INTEGER INPUT VARIABLE SET TO THE NUMBER
+C         OF COLUMNS OF A.
+C
+C       INDROW IS AN INTEGER INPUT ARRAY WHICH CONTAINS THE ROW
+C         INDICES FOR THE NON-ZEROES IN THE MATRIX A.
+C
+C       JPNTR IS AN INTEGER INPUT ARRAY OF LENGTH N + 1 WHICH
+C         SPECIFIES THE LOCATIONS OF THE ROW INDICES IN INDROW.
+C         THE ROW INDICES FOR COLUMN J ARE
+C
+C               INDROW(K), K = JPNTR(J),...,JPNTR(J+1)-1.
+C
+C         NOTE THAT JPNTR(N+1)-1 IS THEN THE NUMBER OF NON-ZERO
+C         ELEMENTS OF THE MATRIX A.
+C
+C       INDCOL IS AN INTEGER INPUT ARRAY WHICH CONTAINS THE
+C         COLUMN INDICES FOR THE NON-ZEROES IN THE MATRIX A.
+C
+C       IPNTR IS AN INTEGER INPUT ARRAY OF LENGTH M + 1 WHICH
+C         SPECIFIES THE LOCATIONS OF THE COLUMN INDICES IN INDCOL.
+C         THE COLUMN INDICES FOR ROW I ARE
+C
+C               INDCOL(K), K = IPNTR(I),...,IPNTR(I+1)-1.
+C
+C         NOTE THAT IPNTR(M+1)-1 IS THEN THE NUMBER OF NON-ZERO
+C         ELEMENTS OF THE MATRIX A.
+C
+C       NDEG IS AN INTEGER INPUT ARRAY OF LENGTH N WHICH SPECIFIES
+C         THE DEGREE SEQUENCE. THE DEGREE OF THE J-TH COLUMN
+C         OF A IS NDEG(J).
+C
+C       LIST IS AN INTEGER OUTPUT ARRAY OF LENGTH N WHICH SPECIFIES
+C         THE SMALLEST-LAST ORDERING OF THE COLUMNS OF A. THE J-TH
+C         COLUMN IN THIS ORDER IS LIST(J).
+C
+C       MAXCLQ IS AN INTEGER OUTPUT VARIABLE SET TO THE SIZE
+C         OF THE LARGEST CLIQUE FOUND DURING THE ORDERING.
+C
+C       IWA1,IWA2,IWA3, AND IWA4 ARE INTEGER WORK ARRAYS OF LENGTH N.
+C
+C       BWA IS A LOGICAL WORK ARRAY OF LENGTH N.
+C
+C     SUBPROGRAMS CALLED
+C
+C       FORTRAN-SUPPLIED ... MIN0
+C
+C     ARGONNE NATIONAL LABORATORY. MINPACK PROJECT. JUNE 1982.
+C     THOMAS F. COLEMAN, BURTON S. GARBOW, JORGE J. MORE
+C
+C     **********
+      INTEGER DEG,HEAD,IC,IP,IPL,IPU,IR,JCOL,JP,JPL,JPU,
+     *        L,MINDEG,NUMDEG,NUMORD
+C
+C     INITIALIZATION BLOCK.
+C
+      MINDEG = N
+      DO 10 JP = 1, N
+         IWA1(JP) = 0
+         BWA(JP) = .FALSE.
+         LIST(JP) = NDEG(JP)
+         MINDEG = MIN0(MINDEG,NDEG(JP))
+   10    CONTINUE
+C
+C     CREATE A DOUBLY-LINKED LIST TO ACCESS THE DEGREES OF THE
+C     COLUMNS. THE POINTERS FOR THE LINKED LIST ARE AS FOLLOWS.
+C
+C     EACH UN-ORDERED COLUMN JCOL IS IN A LIST (THE DEGREE
+C     LIST) OF COLUMNS WITH THE SAME DEGREE.
+C
+C     IWA1(NUMDEG+1) IS THE FIRST COLUMN IN THE NUMDEG LIST
+C     UNLESS IWA1(NUMDEG+1) = 0. IN THIS CASE THERE ARE
+C     NO COLUMNS IN THE NUMDEG LIST.
+C
+C     IWA2(JCOL) IS THE COLUMN BEFORE JCOL IN THE DEGREE LIST
+C     UNLESS IWA2(JCOL) = 0. IN THIS CASE JCOL IS THE FIRST
+C     COLUMN IN THIS DEGREE LIST.
+C
+C     IWA3(JCOL) IS THE COLUMN AFTER JCOL IN THE DEGREE LIST
+C     UNLESS IWA3(JCOL) = 0. IN THIS CASE JCOL IS THE LAST
+C     COLUMN IN THIS DEGREE LIST.
+C
+C     IF JCOL IS AN UN-ORDERED COLUMN, THEN LIST(JCOL) IS THE
+C     DEGREE OF JCOL IN THE GRAPH INDUCED BY THE UN-ORDERED
+C     COLUMNS. IF JCOL IS AN ORDERED COLUMN, THEN LIST(JCOL)
+C     IS THE SMALLEST-LAST ORDER OF COLUMN JCOL.
+C
+      DO 20 JP = 1, N
+         NUMDEG = NDEG(JP)
+         HEAD = IWA1(NUMDEG+1)
+         IWA1(NUMDEG+1) = JP
+         IWA2(JP) = 0
+         IWA3(JP) = HEAD
+         IF (HEAD .GT. 0) IWA2(HEAD) = JP
+   20    CONTINUE
+      MAXCLQ = 0
+      NUMORD = N
+C
+C     BEGINNING OF ITERATION LOOP.
+C
+   30 CONTINUE
+C
+C        MARK THE SIZE OF THE LARGEST CLIQUE
+C        FOUND DURING THE ORDERING.
+C
+         IF (MINDEG + 1 .EQ. NUMORD .AND. MAXCLQ .EQ. 0)
+     *       MAXCLQ = NUMORD
+C
+C        CHOOSE A COLUMN JCOL OF MINIMAL DEGREE MINDEG.
+C
+   40    CONTINUE
+            JCOL = IWA1(MINDEG+1)
+            IF (JCOL .GT. 0) GO TO 50
+            MINDEG = MINDEG + 1
+            GO TO 40
+   50    CONTINUE
+         LIST(JCOL) = NUMORD
+         NUMORD = NUMORD - 1
+C
+C        TERMINATION TEST.
+C
+         IF (NUMORD .EQ. 0) GO TO 120
+C
+C        DELETE COLUMN JCOL FROM THE MINDEG LIST.
+C
+         L = IWA3(JCOL)
+         IWA1(MINDEG+1) = L
+         IF (L .GT. 0) IWA2(L) = 0
+C
+C        FIND ALL COLUMNS ADJACENT TO COLUMN JCOL.
+C
+         BWA(JCOL) = .TRUE.
+         DEG = 0
+C
+C        DETERMINE ALL POSITIONS (IR,JCOL) WHICH CORRESPOND
+C        TO NON-ZEROES IN THE MATRIX.
+C
+         JPL = JPNTR(JCOL)
+         JPU = JPNTR(JCOL+1) - 1
+         IF (JPU .LT. JPL) GO TO 90
+         DO 80 JP = JPL, JPU
+            IR = INDROW(JP)
+C
+C           FOR EACH ROW IR, DETERMINE ALL POSITIONS (IR,IC)
+C           WHICH CORRESPOND TO NON-ZEROES IN THE MATRIX.
+C
+            IPL = IPNTR(IR)
+            IPU = IPNTR(IR+1) - 1
+            DO 70 IP = IPL, IPU
+               IC = INDCOL(IP)
+C
+C              ARRAY BWA MARKS COLUMNS WHICH ARE ADJACENT TO
+C              COLUMN JCOL. ARRAY IWA4 RECORDS THE MARKED COLUMNS.
+C
+               IF (BWA(IC)) GO TO 60
+               BWA(IC) = .TRUE.
+               DEG = DEG + 1
+               IWA4(DEG) = IC
+   60          CONTINUE
+   70          CONTINUE
+   80       CONTINUE
+   90    CONTINUE
+C
+C        UPDATE THE POINTERS TO THE CURRENT DEGREE LISTS.
+C
+         IF (DEG .LT. 1) GO TO 110
+         DO 100 JP = 1, DEG
+            IC = IWA4(JP)
+            NUMDEG = LIST(IC)
+            LIST(IC) = LIST(IC) - 1
+            MINDEG = MIN0(MINDEG,LIST(IC))
+C
+C           DELETE COLUMN IC FROM THE NUMDEG LIST.
+C
+            L = IWA2(IC)
+            IF (L .EQ. 0) IWA1(NUMDEG+1) = IWA3(IC)
+            IF (L .GT. 0) IWA3(L) = IWA3(IC)
+            L = IWA3(IC)
+            IF (L .GT. 0) IWA2(L) = IWA2(IC)
+C
+C           ADD COLUMN IC TO THE NUMDEG-1 LIST.
+C
+            HEAD = IWA1(NUMDEG)
+            IWA1(NUMDEG) = IC
+            IWA2(IC) = 0
+            IWA3(IC) = HEAD
+            IF (HEAD .GT. 0) IWA2(HEAD) = IC
+C
+C           UN-MARK COLUMN IC IN THE ARRAY BWA.
+C
+            BWA(IC) = .FALSE.
+  100       CONTINUE
+  110    CONTINUE
+C
+C        END OF ITERATION LOOP.
+C
+         GO TO 30
+  120 CONTINUE
+C
+C     INVERT THE ARRAY LIST.
+C
+      DO 130 JCOL = 1, N
+         NUMORD = LIST(JCOL)
+         IWA1(NUMORD) = JCOL
+  130    CONTINUE
+      DO 140 JP = 1, N
+         LIST(JP) = IWA1(JP)
+  140    CONTINUE
+      RETURN
+C
+C     LAST CARD OF SUBROUTINE M7SLO.
+C
+      END
+      SUBROUTINE DS7DMP(N, X, Y, Z, K)
+C
+C ***  SET X = DIAG(Z)**K * Y * DIAG(Z)**K
+C ***  FOR X, Y = COMPACTLY STORED LOWER TRIANG. MATRICES
+C ***  K = 1 OR -1.
+C
+      INTEGER N, K
+      DOUBLE PRECISION X(*), Y(*), Z(N)
+      INTEGER I, J, L
+      DOUBLE PRECISION ONE, T
+      DATA ONE/1.D+0/
+C
+      L = 1
+      IF (K .GE. 0) GO TO 30
+      DO 20 I = 1, N
+         T = ONE / Z(I)
+         DO 10 J = 1, I
+            X(L) = T * Y(L) / Z(J)
+            L = L + 1
+ 10         CONTINUE
+ 20      CONTINUE
+      GO TO 999
+C
+ 30   DO 50 I = 1, N
+         T = Z(I)
+         DO 40 J = 1, I
+            X(L) = T * Y(L) * Z(J)
+            L = L + 1
+ 40         CONTINUE
+ 50      CONTINUE
+ 999  RETURN
+C  ***  LAST CARD OF DS7DMP FOLLOWS  ***
+      END
+      SUBROUTINE DS7BQN(B, D, DST, IPIV, IPIV1, IPIV2, KB, L, LV, NS,
+     1                  P, P1, STEP, TD, TG, V, W, X, X0)
+C
+C  ***  COMPUTE BOUNDED MODIFIED NEWTON STEP  ***
+C
+      INTEGER KB, LV, NS, P, P1
+      INTEGER IPIV(P), IPIV1(P), IPIV2(P)
+      DOUBLE PRECISION B(2,P), D(P), DST(P), L(*),
+     1                 STEP(P), TD(P), TG(P), V(LV), W(P), X(P),
+     2                 X0(P)
+C     DIMENSION L(P*(P+1)/2)
+C
+      DOUBLE PRECISION DD7TPR, DR7MDC, DV2NRM
+      EXTERNAL DD7TPR, I7SHFT, DL7ITV, DL7IVM, DQ7RSH, DR7MDC, DV2NRM,
+     1        DV2AXY,DV7CPY, DV7IPR, DV7SCP, DV7SHF
+C
+C  ***  LOCAL VARIABLES  ***
+C
+      INTEGER I, J, K, P0, P1M1
+      DOUBLE PRECISION ALPHA, DST0, DST1, DSTMAX, DSTMIN, DX, GTS, T,
+     1                 TI, T1, XI
+      DOUBLE PRECISION FUDGE, HALF, MEPS2, ONE, TWO, ZERO
+C
+C  ***  V SUBSCRIPTS  ***
+C
+      INTEGER DSTNRM, GTSTEP, PHMNFC, PHMXFC, PREDUC, RADIUS, STPPAR
+C
+      PARAMETER (DSTNRM=2, GTSTEP=4, PHMNFC=20, PHMXFC=21, PREDUC=7,
+     1           RADIUS=8, STPPAR=5)
+      SAVE MEPS2
+C
+      DATA FUDGE/1.0001D+0/, HALF/0.5D+0/, MEPS2/0.D+0/,
+     1     ONE/1.0D+0/, TWO/2.D+0/, ZERO/0.D+0/
+C
+C+++++++++++++++++++++++++++++++  BODY  ++++++++++++++++++++++++++++++++
+C
+      DSTMAX = FUDGE * (ONE + V(PHMXFC)) * V(RADIUS)
+      DSTMIN = (ONE + V(PHMNFC)) * V(RADIUS)
+      DST1 = ZERO
+      IF (MEPS2 .LE. ZERO) MEPS2 = TWO * DR7MDC(3)
+      P0 = P1
+      NS = 0
+      DO 10 I = 1, P
+         IPIV1(I) = I
+         IPIV2(I) = I
+ 10      CONTINUE
+      DO 20 I = 1, P1
+ 20      W(I) = -STEP(I) * TD(I)
+      ALPHA = DABS(V(STPPAR))
+      V(PREDUC) = ZERO
+      GTS = -V(GTSTEP)
+      IF (KB .LT. 0) CALL DV7SCP(P, DST, ZERO)
+      KB = 1
+C
+C     ***  -W = D TIMES RESTRICTED NEWTON STEP FROM X + DST/D.
+C
+C     ***  FIND T SUCH THAT X - T*W IS STILL FEASIBLE.
+C
+ 30   T = ONE
+      K = 0
+      DO 60 I = 1, P1
+         J = IPIV(I)
+         DX = W(I) / D(J)
+         XI = X(J) - DX
+         IF (XI .LT. B(1,J)) GO TO 40
+         IF (XI .LE. B(2,J)) GO TO 60
+              TI = ( X(J)  -  B(2,J) ) / DX
+              K = I
+              GO TO 50
+ 40      TI = ( X(J)  -  B(1,J) ) / DX
+              K = -I
+ 50      IF (T .LE. TI) GO TO 60
+              T = TI
+ 60      CONTINUE
+C
+      IF (P .GT. P1) CALL DV7CPY(P-P1, STEP(P1+1), DST(P1+1))
+      CALL DV2AXY(P1, STEP, -T, W, DST)
+      DST0 = DST1
+      DST1 = DV2NRM(P, STEP)
+C
+C  ***  CHECK FOR OVERSIZE STEP  ***
+C
+      IF (DST1 .LE. DSTMAX) GO TO 80
+      IF (P1 .GE. P0) GO TO 70
+         IF (DST0 .LT. DSTMIN) KB = 0
+         GO TO 110
+C
+ 70   K = 0
+C
+C  ***  UPDATE DST, TG, AND V(PREDUC)  ***
+C
+ 80   V(DSTNRM) = DST1
+      CALL DV7CPY(P1, DST, STEP)
+      T1 = ONE - T
+      DO 90 I = 1, P1
+ 90      TG(I) = T1 * TG(I)
+      IF (ALPHA .GT. ZERO) CALL DV2AXY(P1, TG, T*ALPHA, W, TG)
+      V(PREDUC) = V(PREDUC) + T*((ONE - HALF*T)*GTS +
+     1                        HALF*ALPHA*T*DD7TPR(P1,W,W))
+      IF (K .EQ. 0) GO TO 110
+C
+C     ***  PERMUTE L, ETC. IF NECESSARY  ***
+C
+      P1M1 = P1 - 1
+      J = IABS(K)
+      IF (J .EQ. P1) GO TO 100
+         NS = NS + 1
+         IPIV2(P1) = J
+         CALL DQ7RSH(J, P1, .FALSE., TG, L, W)
+         CALL I7SHFT(P1, J, IPIV)
+         CALL I7SHFT(P1, J, IPIV1)
+         CALL DV7SHF(P1, J, TG)
+         CALL DV7SHF(P1, J, DST)
+ 100  IF (K .LT. 0) IPIV(P1) = -IPIV(P1)
+      P1 = P1M1
+      IF (P1 .LE. 0) GO TO 110
+      CALL DL7IVM(P1, W, L, TG)
+      GTS = DD7TPR(P1, W, W)
+      CALL DL7ITV(P1, W, L, W)
+      GO TO 30
+C
+C     ***  UNSCALE STEP  ***
+C
+ 110  DO 120 I = 1, P
+         J = IABS(IPIV(I))
+         STEP(J) = DST(I) / D(J)
+ 120     CONTINUE
+C
+C  ***  FUDGE STEP TO ENSURE THAT IT FORCES APPROPRIATE COMPONENTS
+C  ***  TO THEIR BOUNDS  ***
+C
+      IF (P1 .GE. P0) GO TO 150
+      K = P1 + 1
+      DO 140 I = K, P0
+         J = IPIV(I)
+         T = MEPS2
+         IF (J .GT. 0) GO TO 130
+            T = -T
+            J = -J
+            IPIV(I) = J
+ 130     T = T * DMAX1(DABS(X(J)), DABS(X0(J)))
+         STEP(J) = STEP(J) + T
+ 140     CONTINUE
+C
+ 150  CALL DV2AXY(P, X, ONE, STEP, X0)
+      IF (NS .GT. 0) CALL DV7IPR(P0, IPIV1, TD)
+      RETURN
+C  ***  LAST LINE OF DS7BQN FOLLOWS  ***
+      END
+      SUBROUTINE N7MSRT(N,NMAX,NUM,MODE,INDEX,LAST,NEXT)
+      INTEGER N,NMAX,MODE
+      INTEGER NUM(N),INDEX(N),LAST(1),NEXT(N)
+C     **********.
+C
+C     SUBROUTINE N7MSRT
+C
+C     GIVEN A SEQUENCE OF INTEGERS, THIS SUBROUTINE GROUPS
+C     TOGETHER THOSE INDICES WITH THE SAME SEQUENCE VALUE
+C     AND, OPTIONALLY, SORTS THE SEQUENCE INTO EITHER
+C     ASCENDING OR DESCENDING ORDER.
+C
+C     THE SEQUENCE OF INTEGERS IS DEFINED BY THE ARRAY NUM,
+C     AND IT IS ASSUMED THAT THE INTEGERS ARE EACH FROM THE SET
+C     0,1,...,NMAX. ON OUTPUT THE INDICES K SUCH THAT NUM(K) = L
+C     FOR ANY L = 0,1,...,NMAX CAN BE OBTAINED FROM THE ARRAYS
+C     LAST AND NEXT AS FOLLOWS.
+C
+C           K = LAST(L+1)
+C           WHILE (K .NE. 0) K = NEXT(K)
+C
+C     OPTIONALLY, THE SUBROUTINE PRODUCES AN ARRAY INDEX SO THAT
+C     THE SEQUENCE NUM(INDEX(I)), I = 1,2,...,N IS SORTED.
+C
+C     THE SUBROUTINE STATEMENT IS
+C
+C       SUBROUTINE N7MSRT(N,NMAX,NUM,MODE,INDEX,LAST,NEXT)
+C
+C     WHERE
+C
+C       N IS A POSITIVE INTEGER INPUT VARIABLE.
+C
+C       NMAX IS A POSITIVE INTEGER INPUT VARIABLE.
+C
+C       NUM IS AN INPUT ARRAY OF LENGTH N WHICH CONTAINS THE
+C         SEQUENCE OF INTEGERS TO BE GROUPED AND SORTED. IT
+C         IS ASSUMED THAT THE INTEGERS ARE EACH FROM THE SET
+C         0,1,...,NMAX.
+C
+C       MODE IS AN INTEGER INPUT VARIABLE. THE SEQUENCE NUM IS
+C         SORTED IN ASCENDING ORDER IF MODE IS POSITIVE AND IN
+C         DESCENDING ORDER IF MODE IS NEGATIVE. IF MODE IS 0,
+C         NO SORTING IS DONE.
+C
+C       INDEX IS AN INTEGER OUTPUT ARRAY OF LENGTH N SET SO
+C         THAT THE SEQUENCE
+C
+C               NUM(INDEX(I)), I = 1,2,...,N
+C
+C         IS SORTED ACCORDING TO THE SETTING OF MODE. IF MODE
+C         IS 0, INDEX IS NOT REFERENCED.
+C
+C       LAST IS AN INTEGER OUTPUT ARRAY OF LENGTH NMAX + 1. THE
+C         INDEX OF NUM FOR THE LAST OCCURRENCE OF L IS LAST(L+1)
+C         FOR ANY L = 0,1,...,NMAX UNLESS LAST(L+1) = 0. IN
+C         THIS CASE L DOES NOT APPEAR IN NUM.
+C
+C       NEXT IS AN INTEGER OUTPUT ARRAY OF LENGTH N. IF
+C         NUM(K) = L, THEN THE INDEX OF NUM FOR THE PREVIOUS
+C         OCCURRENCE OF L IS NEXT(K) FOR ANY L = 0,1,...,NMAX
+C         UNLESS NEXT(K) = 0. IN THIS CASE THERE IS NO PREVIOUS
+C         OCCURRENCE OF L IN NUM.
+C
+C     ARGONNE NATIONAL LABORATORY. MINPACK PROJECT. JUNE 1982.
+C     THOMAS F. COLEMAN, BURTON S. GARBOW, JORGE J. MORE
+C
+C     **********
+      INTEGER I,J,JP,K,L,NMAXP1,NMAXP2
+C
+C     DETERMINE THE ARRAYS NEXT AND LAST.
+C
+      NMAXP1 = NMAX + 1
+      DO 10 I = 1, NMAXP1
+         LAST(I) = 0
+   10    CONTINUE
+      DO 20 K = 1, N
+         L = NUM(K)
+         NEXT(K) = LAST(L+1)
+         LAST(L+1) = K
+   20    CONTINUE
+      IF (MODE .EQ. 0) GO TO 60
+C
+C     STORE THE POINTERS TO THE SORTED ARRAY IN INDEX.
+C
+      I = 1
+      NMAXP2 = NMAXP1 + 1
+      DO 50 J = 1, NMAXP1
+         JP = J
+         IF (MODE .LT. 0) JP = NMAXP2 - J
+         K = LAST(JP)
+   30    CONTINUE
+            IF (K .EQ. 0) GO TO 40
+            INDEX(I) = K
+            I = I + 1
+            K = NEXT(K)
+            GO TO 30
+   40    CONTINUE
+   50    CONTINUE
+   60 CONTINUE
+      RETURN
+C
+C     LAST CARD OF SUBROUTINE N7MSRT.
+C
+      END
+      SUBROUTINE DG7LIT(D, G, IV, LIV, LV, P, PS, V, X, Y)
+C
+C  ***  CARRY OUT NL2SOL-LIKE ITERATIONS FOR GENERALIZED LINEAR   ***
+C  ***  REGRESSION PROBLEMS (AND OTHERS OF SIMILAR STRUCTURE)     ***
+C
+C  ***  PARAMETER DECLARATIONS  ***
+C
+      INTEGER LIV, LV, P, PS
+      INTEGER IV(LIV)
+      DOUBLE PRECISION D(P), G(P), V(LV), X(P), Y(P)
+C
+C--------------------------  PARAMETER USAGE  --------------------------
+C
+C D.... SCALE VECTOR.
+C IV... INTEGER VALUE ARRAY.
+C LIV.. LENGTH OF IV.  MUST BE AT LEAST 82.
+C LH... LENGTH OF H = P*(P+1)/2.
+C LV... LENGTH OF V.  MUST BE AT LEAST P*(3*P + 19)/2 + 7.
+C G.... GRADIENT AT X (WHEN IV(1) = 2).
+C P.... NUMBER OF PARAMETERS (COMPONENTS IN X).
+C PS... NUMBER OF NONZERO ROWS AND COLUMNS IN S.
+C V.... FLOATING-POINT VALUE ARRAY.
+C X.... PARAMETER VECTOR.
+C Y.... PART OF YIELD VECTOR (WHEN IV(1)= 2, SCRATCH OTHERWISE).
+C
+C  ***  DISCUSSION  ***
+C
+C       DG7LIT PERFORMS NL2SOL-LIKE ITERATIONS FOR A VARIETY OF
+C     REGRESSION PROBLEMS THAT ARE SIMILAR TO NONLINEAR LEAST-SQUARES
+C     IN THAT THE HESSIAN IS THE SUM OF TWO TERMS, A READILY-COMPUTED
+C     FIRST-ORDER TERM AND A SECOND-ORDER TERM.  THE CALLER SUPPLIES
+C     THE FIRST-ORDER TERM OF THE HESSIAN IN HC (LOWER TRIANGLE, STORED
+C     COMPACTLY BY ROWS IN V, STARTING AT IV(HC)), AND DG7LIT BUILDS AN
+C     APPROXIMATION, S, TO THE SECOND-ORDER TERM.  THE CALLER ALSO
+C     PROVIDES THE FUNCTION VALUE, GRADIENT, AND PART OF THE YIELD
+C     VECTOR USED IN UPDATING S. DG7LIT DECIDES DYNAMICALLY WHETHER OR
+C     NOT TO USE S WHEN CHOOSING THE NEXT STEP TO TRY...  THE HESSIAN
+C     APPROXIMATION USED IS EITHER HC ALONE (GAUSS-NEWTON MODEL) OR
+C     HC + S (AUGMENTED MODEL).
+C
+C        IF PS .LT. P, THEN ROWS AND COLUMNS PS+1...P OF S ARE KEPT
+C     CONSTANT.  THEY WILL BE ZERO UNLESS THE CALLER SETS IV(INITS) TO
+C     1 OR 2 AND SUPPLIES NONZERO VALUES FOR THEM, OR THE CALLER SETS
+C     IV(INITS) TO 3 OR 4 AND THE FINITE-DIFFERENCE INITIAL S THEN
+C     COMPUTED HAS NONZERO VALUES IN THESE ROWS.
+C
+C        IF IV(INITS) IS 3 OR 4, THEN THE INITIAL S IS COMPUTED BY
+C     FINITE DIFFERENCES.  3 MEANS USE FUNCTION DIFFERENCES, 4 MEANS
+C     USE GRADIENT DIFFERENCES.  FINITE DIFFERENCING IS DONE THE SAME
+C     WAY AS IN COMPUTING A COVARIANCE MATRIX (WITH IV(COVREQ) = -1, -2,
+C     1, OR 2).
+C
+C        FOR UPDATING S,DG7LIT ASSUMES THAT THE GRADIENT HAS THE FORM
+C     OF A SUM OVER I OF RHO(I,X)*GRAD(R(I,X)), WHERE GRAD DENOTES THE
+C     GRADIENT WITH RESPECT TO X.  THE TRUE SECOND-ORDER TERM THEN IS
+C     THE SUM OVER I OF RHO(I,X)*HESSIAN(R(I,X)).  IF X = X0 + STEP,
+C     THEN WE WISH TO UPDATE S SO THAT S*STEP IS THE SUM OVER I OF
+C     RHO(I,X)*(GRAD(R(I,X)) - GRAD(R(I,X0))).  THE CALLER MUST SUPPLY
+C     PART OF THIS IN Y, NAMELY THE SUM OVER I OF
+C     RHO(I,X)*GRAD(R(I,X0)), WHEN CALLING DG7LIT WITH IV(1) = 2 AND
+C     IV(MODE) = 0 (WHERE MODE = 38).  G THEN CONTANS THE OTHER PART,
+C     SO THAT THE DESIRED YIELD VECTOR IS G - Y.  IF PS .LT. P, THEN
+C     THE ABOVE DISCUSSION APPLIES ONLY TO THE FIRST PS COMPONENTS OF
+C     GRAD(R(I,X)), STEP, AND Y.
+C
+C        PARAMETERS IV, P, V, AND X ARE THE SAME AS THE CORRESPONDING
+C     ONES TO NL2SOL (WHICH SEE), EXCEPT THAT V CAN BE SHORTER
+C     (SINCE THE PART OF V THAT NL2SOL USES FOR STORING D, J, AND R IS
+C     NOT NEEDED).  MOREOVER, COMPARED WITH NL2SOL, IV(1) MAY HAVE THE
+C     TWO ADDITIONAL OUTPUT VALUES 1 AND 2, WHICH ARE EXPLAINED BELOW,
+C     AS IS THE USE OF IV(TOOBIG) AND IV(NFGCAL).  THE VALUES IV(D),
+C     IV(J), AND IV(R), WHICH ARE OUTPUT VALUES FROM NL2SOL (AND
+C     NL2SNO), ARE NOT REFERENCED BY DG7LIT OR THE SUBROUTINES IT CALLS.
+C
+C        WHEN DG7LIT IS FIRST CALLED, I.E., WHEN DG7LIT IS CALLED WITH
+C     IV(1) = 0 OR 12, V(F), G, AND HC NEED NOT BE INITIALIZED.  TO
+C     OBTAIN THESE STARTING VALUES,DG7LIT RETURNS FIRST WITH IV(1) = 1,
+C     THEN WITH IV(1) = 2, WITH IV(MODE) = -1 IN BOTH CASES.  ON
+C     SUBSEQUENT RETURNS WITH IV(1) = 2, IV(MODE) = 0 IMPLIES THAT
+C     Y MUST ALSO BE SUPPLIED.  (NOTE THAT Y IS USED FOR SCRATCH -- ITS
+C     INPUT CONTENTS ARE LOST.  BY CONTRAST, HC IS NEVER CHANGED.)
+C     ONCE CONVERGENCE HAS BEEN OBTAINED, IV(RDREQ) AND IV(COVREQ) MAY
+C     IMPLY THAT A FINITE-DIFFERENCE HESSIAN SHOULD BE COMPUTED FOR USE
+C     IN COMPUTING A COVARIANCE MATRIX.  IN THIS CASE DG7LIT WILL MAKE A
+C     NUMBER OF RETURNS WITH IV(1) = 1 OR 2 AND IV(MODE) POSITIVE.
+C     WHEN IV(MODE) IS POSITIVE, Y SHOULD NOT BE CHANGED.
+C
+C IV(1) = 1 MEANS THE CALLER SHOULD SET V(F) (I.E., V(10)) TO F(X), THE
+C             FUNCTION VALUE AT X, AND CALL DG7LIT AGAIN, HAVING CHANGED
+C             NONE OF THE OTHER PARAMETERS.  AN EXCEPTION OCCURS IF F(X)
+C             CANNOT BE EVALUATED (E.G. IF OVERFLOW WOULD OCCUR), WHICH
+C             MAY HAPPEN BECAUSE OF AN OVERSIZED STEP.  IN THIS CASE
+C             THE CALLER SHOULD SET IV(TOOBIG) = IV(2) TO 1, WHICH WILL
+C             CAUSE DG7LIT TO IGNORE V(F) AND TRY A SMALLER STEP.  NOTE
+C             THAT THE CURRENT FUNCTION EVALUATION COUNT IS AVAILABLE
+C             IN IV(NFCALL) = IV(6).  THIS MAY BE USED TO IDENTIFY
+C             WHICH COPY OF SAVED INFORMATION SHOULD BE USED IN COM-
+C             PUTING G, HC, AND Y THE NEXT TIME DG7LIT RETURNS WITH
+C             IV(1) = 2.  SEE MLPIT FOR AN EXAMPLE OF THIS.
+C IV(1) = 2 MEANS THE CALLER SHOULD SET G TO G(X), THE GRADIENT OF F AT
+C             X.  THE CALLER SHOULD ALSO SET HC TO THE GAUSS-NEWTON
+C             HESSIAN AT X.  IF IV(MODE) = 0, THEN THE CALLER SHOULD
+C             ALSO COMPUTE THE PART OF THE YIELD VECTOR DESCRIBED ABOVE.
+C             THE CALLER SHOULD THEN CALL DG7LIT AGAIN (WITH IV(1) = 2).
+C             THE CALLER MAY ALSO CHANGE D AT THIS TIME, BUT SHOULD NOT
+C             CHANGE X.  NOTE THAT IV(NFGCAL) = IV(7) CONTAINS THE
+C             VALUE THAT IV(NFCALL) HAD DURING THE RETURN WITH
+C             IV(1) = 1 IN WHICH X HAD THE SAME VALUE AS IT NOW HAS.
+C             IV(NFGCAL) IS EITHER IV(NFCALL) OR IV(NFCALL) - 1.  MLPIT
+C             IS AN EXAMPLE WHERE THIS INFORMATION IS USED.  IF G OR HC
+C             CANNOT BE EVALUATED AT X, THEN THE CALLER MAY SET
+C             IV(TOOBIG) TO 1, IN WHICH CASE DG7LIT WILL RETURN WITH
+C             IV(1) = 15.
+C
+C  ***  GENERAL  ***
+C
+C     CODED BY DAVID M. GAY.
+C     THIS SUBROUTINE WAS WRITTEN IN CONNECTION WITH RESEARCH
+C     SUPPORTED IN PART BY D.O.E. GRANT EX-76-A-01-2295 TO MIT/CCREMS.
+C
+C        (SEE NL2SOL FOR REFERENCES.)
+C
+C+++++++++++++++++++++++++++  DECLARATIONS  ++++++++++++++++++++++++++++
+C
+C  ***  LOCAL VARIABLES  ***
+C
+      INTEGER DUMMY, DIG1, G01, H1, HC1, I, IPIV1, J, K, L, LMAT1,
+     1        LSTGST, PP1O2, QTR1, RMAT1, RSTRST, STEP1, STPMOD, S1,
+     2        TEMP1, TEMP2, W1, X01
+      DOUBLE PRECISION E, STTSST, T, T1
+C
+C     ***  CONSTANTS  ***
+C
+      DOUBLE PRECISION HALF, NEGONE, ONE, ONEP2, ZERO
+C
+C  ***  EXTERNAL FUNCTIONS AND SUBROUTINES  ***
+C
+      LOGICAL STOPX
+      DOUBLE PRECISION DD7TPR, DL7SVX, DL7SVN, DRLDST, DR7MDC, DV2NRM
+      EXTERNAL DA7SST, DD7TPR,DF7HES,DG7QTS,DITSUM, DL7MST,DL7SRT,
+     1         DL7SQR, DL7SVX, DL7SVN, DL7TVM,DL7VML,DPARCK, DRLDST,
+     2         DR7MDC, DS7LUP, DS7LVM, STOPX,DV2AXY,DV7CPY, DV7SCP,
+     3         DV2NRM
+C
+C DA7SST.... ASSESSES CANDIDATE STEP.
+C DD7TPR... RETURNS INNER PRODUCT OF TWO VECTORS.
+C DF7HES.... COMPUTE FINITE-DIFFERENCE HESSIAN (FOR COVARIANCE).
+C DG7QTS.... COMPUTES GOLDFELD-QUANDT-TROTTER STEP (AUGMENTED MODEL).
+C DITSUM.... PRINTS ITERATION SUMMARY AND INFO ON INITIAL AND FINAL X.
+C DL7MST... COMPUTES LEVENBERG-MARQUARDT STEP (GAUSS-NEWTON MODEL).
+C DL7SRT.... COMPUTES CHOLESKY FACTOR OF (LOWER TRIANG. OF) SYM. MATRIX.
+C DL7SQR... COMPUTES L * L**T FROM LOWER TRIANGULAR MATRIX L.
+C DL7TVM... COMPUTES L**T * V, V = VECTOR, L = LOWER TRIANGULAR MATRIX.
+C DL7SVX... ESTIMATES LARGEST SING. VALUE OF LOWER TRIANG. MATRIX.
+C DL7SVN... ESTIMATES SMALLEST SING. VALUE OF LOWER TRIANG. MATRIX.
+C DL7VML.... COMPUTES L * V, V = VECTOR, L = LOWER TRIANGULAR MATRIX.
+C DPARCK.... CHECK VALIDITY OF IV AND V INPUT COMPONENTS.
+C DRLDST... COMPUTES V(RELDX) = RELATIVE STEP SIZE.
+C DR7MDC... RETURNS MACHINE-DEPENDENT CONSTANTS.
+C DS7LUP... PERFORMS QUASI-NEWTON UPDATE ON COMPACTLY STORED LOWER TRI-
+C             ANGLE OF A SYMMETRIC MATRIX.
+C STOPX.... RETURNS .TRUE. IF THE BREAK KEY HAS BEEN PRESSED.
+C DV2AXY.... COMPUTES SCALAR TIMES ONE VECTOR PLUS ANOTHER.
+C DV7CPY.... COPIES ONE VECTOR TO ANOTHER.
+C DV7SCP... SETS ALL ELEMENTS OF A VECTOR TO A SCALAR.
+C DV2NRM... RETURNS THE 2-NORM OF A VECTOR.
+C
+C  ***  SUBSCRIPTS FOR IV AND V  ***
+C
+      INTEGER CNVCOD, COSMIN, COVMAT, COVREQ, DGNORM, DIG, DSTNRM, F,
+     1        FDH, FDIF, FUZZ, F0, GTSTEP, H, HC, IERR, INCFAC, INITS,
+     2        IPIVOT, IRC, KAGQT, KALM, LMAT, LMAX0, LMAXS, MODE, MODEL,
+     3        MXFCAL, MXITER, NEXTV, NFCALL, NFGCAL, NFCOV, NGCOV,
+     4        NGCALL, NITER, NVSAVE, PHMXFC, PREDUC, QTR, RADFAC,
+     5        RADINC, RADIUS, RAD0, RCOND, RDREQ, REGD, RELDX, RESTOR,
+     6        RMAT, S, SIZE, STEP, STGLIM, STLSTG, STPPAR, SUSED,
+     7        SWITCH, TOOBIG, TUNER4, TUNER5, VNEED, VSAVE, W, WSCALE,
+     8        XIRC, X0
+C
+C  ***  IV SUBSCRIPT VALUES  ***
+C
+      PARAMETER (CNVCOD=55, COVMAT=26, COVREQ=15, DIG=37, FDH=74, H=56,
+     1           HC=71, IERR=75, INITS=25, IPIVOT=76, IRC=29, KAGQT=33,
+     2           KALM=34, LMAT=42, MODE=35, MODEL=5, MXFCAL=17,
+     3           MXITER=18, NEXTV=47, NFCALL=6, NFGCAL=7, NFCOV=52,
+     4           NGCOV=53, NGCALL=30, NITER=31, QTR=77, RADINC=8,
+     5           RDREQ=57, REGD=67, RESTOR=9, RMAT=78, S=62, STEP=40,
+     6           STGLIM=11, STLSTG=41, SUSED=64, SWITCH=12, TOOBIG=2,
+     7           VNEED=4, VSAVE=60, W=65, XIRC=13, X0=43)
+C
+C  ***  V SUBSCRIPT VALUES  ***
+C
+      PARAMETER (COSMIN=47, DGNORM=1, DSTNRM=2, F=10, FDIF=11, FUZZ=45,
+     1           F0=13, GTSTEP=4, INCFAC=23, LMAX0=35, LMAXS=36,
+     2           NVSAVE=9, PHMXFC=21, PREDUC=7, RADFAC=16, RADIUS=8,
+     3           RAD0=9, RCOND=53, RELDX=17, SIZE=55, STPPAR=5,
+     4           TUNER4=29, TUNER5=30, WSCALE=56)
+C
+C
+      PARAMETER (HALF=0.5D+0, NEGONE=-1.D+0, ONE=1.D+0, ONEP2=1.2D+0,
+     1           ZERO=0.D+0)
+C
+C+++++++++++++++++++++++++++++++  BODY  ++++++++++++++++++++++++++++++++
+C
+      I = IV(1)
+      IF (I .EQ. 1) GO TO 40
+      IF (I .EQ. 2) GO TO 50
+C
+      IF (I .EQ. 12 .OR. I .EQ. 13)
+     1     IV(VNEED) = IV(VNEED) + P*(3*P + 19)/2 + 7
+      CALL DPARCK(1, D, IV, LIV, LV, P, V)
+      I = IV(1) - 2
+      IF (I .GT. 12) GO TO 999
+      GO TO (290, 290, 290, 290, 290, 290, 170, 120, 170, 10, 10, 20), I
+C
+C  ***  STORAGE ALLOCATION  ***
+C
+ 10   PP1O2 = P * (P + 1) / 2
+      IV(S) = IV(LMAT) + PP1O2
+      IV(X0) = IV(S) + PP1O2
+      IV(STEP) = IV(X0) + P
+      IV(STLSTG) = IV(STEP) + P
+      IV(DIG) = IV(STLSTG) + P
+      IV(W) = IV(DIG) + P
+      IV(H) = IV(W) + 4*P + 7
+      IV(NEXTV) = IV(H) + PP1O2
+      IF (IV(1) .NE. 13) GO TO 20
+         IV(1) = 14
+         GO TO 999
+C
+C  ***  INITIALIZATION  ***
+C
+ 20   IV(NITER) = 0
+      IV(NFCALL) = 1
+      IV(NGCALL) = 1
+      IV(NFGCAL) = 1
+      IV(MODE) = -1
+      IV(STGLIM) = 2
+      IV(TOOBIG) = 0
+      IV(CNVCOD) = 0
+      IV(COVMAT) = 0
+      IV(NFCOV) = 0
+      IV(NGCOV) = 0
+      IV(RADINC) = 0
+      IV(RESTOR) = 0
+      IV(FDH) = 0
+      V(RAD0) = ZERO
+      V(STPPAR) = ZERO
+      V(RADIUS) = V(LMAX0) / (ONE + V(PHMXFC))
+C
+C  ***  SET INITIAL MODEL AND S MATRIX  ***
+C
+      IV(MODEL) = 1
+      IF (IV(S) .LT. 0) GO TO 999
+      IF (IV(INITS) .GT. 1) IV(MODEL) = 2
+      S1 = IV(S)
+      IF (IV(INITS) .EQ. 0 .OR. IV(INITS) .GT. 2)
+     1   CALL DV7SCP(P*(P+1)/2, V(S1), ZERO)
+      IV(1) = 1
+      J = IV(IPIVOT)
+      IF (J .LE. 0) GO TO 999
+      DO 30 I = 1, P
+         IV(J) = I
+         J = J + 1
+ 30      CONTINUE
+      GO TO 999
+C
+C  ***  NEW FUNCTION VALUE  ***
+C
+ 40   IF (IV(MODE) .EQ. 0) GO TO 290
+      IF (IV(MODE) .GT. 0) GO TO 520
+C
+      IV(1) = 2
+      IF (IV(TOOBIG) .EQ. 0) GO TO 999
+         IV(1) = 63
+         GO TO 999
+C
+C  ***  NEW GRADIENT  ***
+C
+ 50   IV(KALM) = -1
+      IV(KAGQT) = -1
+      IV(FDH) = 0
+      IF (IV(MODE) .GT. 0) GO TO 520
+C
+C  ***  MAKE SURE GRADIENT COULD BE COMPUTED  ***
+C
+      IF (IV(TOOBIG) .EQ. 0) GO TO 60
+         IV(1) = 65
+         GO TO 999
+ 60   IF (IV(HC) .LE. 0 .AND. IV(RMAT) .LE. 0) GO TO 610
+C
+C  ***  COMPUTE  D**-1 * GRADIENT  ***
+C
+      DIG1 = IV(DIG)
+      K = DIG1
+      DO 70 I = 1, P
+         V(K) = G(I) / D(I)
+         K = K + 1
+ 70      CONTINUE
+      V(DGNORM) = DV2NRM(P, V(DIG1))
+C
+      IF (IV(CNVCOD) .NE. 0) GO TO 510
+      IF (IV(MODE) .EQ. 0) GO TO 440
+      IV(MODE) = 0
+      V(F0) = V(F)
+      IF (IV(INITS) .LE. 2) GO TO 100
+C
+C  ***  ARRANGE FOR FINITE-DIFFERENCE INITIAL S  ***
+C
+      IV(XIRC) = IV(COVREQ)
+      IV(COVREQ) = -1
+      IF (IV(INITS) .GT. 3) IV(COVREQ) = 1
+      IV(CNVCOD) = 70
+      GO TO 530
+C
+C  ***  COME TO NEXT STMT AFTER COMPUTING F.D. HESSIAN FOR INIT. S  ***
+C
+ 80   IV(CNVCOD) = 0
+      IV(MODE) = 0
+      IV(NFCOV) = 0
+      IV(NGCOV) = 0
+      IV(COVREQ) = IV(XIRC)
+      S1 = IV(S)
+      PP1O2 = PS * (PS + 1) / 2
+      HC1 = IV(HC)
+      IF (HC1 .LE. 0) GO TO 90
+         CALL DV2AXY(PP1O2, V(S1), NEGONE, V(HC1), V(H1))
+         GO TO 100
+ 90   RMAT1 = IV(RMAT)
+      CALL DL7SQR(PS, V(S1), V(RMAT1))
+      CALL DV2AXY(PP1O2, V(S1), NEGONE, V(S1), V(H1))
+ 100  IV(1) = 2
+C
+C
+C-----------------------------  MAIN LOOP  -----------------------------
+C
+C
+C  ***  PRINT ITERATION SUMMARY, CHECK ITERATION LIMIT  ***
+C
+ 110  CALL DITSUM(D, G, IV, LIV, LV, P, V, X)
+ 120  K = IV(NITER)
+      IF (K .LT. IV(MXITER)) GO TO 130
+         IV(1) = 10
+         GO TO 999
+ 130  IV(NITER) = K + 1
+C
+C  ***  UPDATE RADIUS  ***
+C
+      IF (K .EQ. 0) GO TO 150
+      STEP1 = IV(STEP)
+      DO 140 I = 1, P
+         V(STEP1) = D(I) * V(STEP1)
+         STEP1 = STEP1 + 1
+ 140     CONTINUE
+      STEP1 = IV(STEP)
+      T = V(RADFAC) * DV2NRM(P, V(STEP1))
+      IF (V(RADFAC) .LT. ONE .OR. T .GT. V(RADIUS)) V(RADIUS) = T
+C
+C  ***  INITIALIZE FOR START OF NEXT ITERATION  ***
+C
+ 150  X01 = IV(X0)
+      V(F0) = V(F)
+      IV(IRC) = 4
+      IV(H) = -IABS(IV(H))
+      IV(SUSED) = IV(MODEL)
+C
+C     ***  COPY X TO X0  ***
+C
+      CALL DV7CPY(P, V(X01), X)
+C
+C  ***  CHECK STOPX AND FUNCTION EVALUATION LIMIT  ***
+C
+ 160  IF (.NOT. STOPX(DUMMY)) GO TO 180
+         IV(1) = 11
+         GO TO 190
+C
+C     ***  COME HERE WHEN RESTARTING AFTER FUNC. EVAL. LIMIT OR STOPX.
+C
+ 170  IF (V(F) .GE. V(F0)) GO TO 180
+         V(RADFAC) = ONE
+         K = IV(NITER)
+         GO TO 130
+C
+ 180  IF (IV(NFCALL) .LT. IV(MXFCAL) + IV(NFCOV)) GO TO 200
+         IV(1) = 9
+ 190     IF (V(F) .GE. V(F0)) GO TO 999
+C
+C        ***  IN CASE OF STOPX OR FUNCTION EVALUATION LIMIT WITH
+C        ***  IMPROVED V(F), EVALUATE THE GRADIENT AT X.
+C
+              IV(CNVCOD) = IV(1)
+              GO TO 430
+C
+C. . . . . . . . . . . . .  COMPUTE CANDIDATE STEP  . . . . . . . . . .
+C
+ 200  STEP1 = IV(STEP)
+      W1 = IV(W)
+      H1 = IV(H)
+      T1 = ONE
+      IF (IV(MODEL) .EQ. 2) GO TO 210
+         T1 = ZERO
+C
+C        ***  COMPUTE LEVENBERG-MARQUARDT STEP IF POSSIBLE...
+C
+         RMAT1 = IV(RMAT)
+         IF (RMAT1 .LE. 0) GO TO 210
+         QTR1 = IV(QTR)
+         IF (QTR1 .LE. 0) GO TO 210
+         IPIV1 = IV(IPIVOT)
+         CALL DL7MST(D, G, IV(IERR), IV(IPIV1), IV(KALM), P, V(QTR1),
+     1               V(RMAT1), V(STEP1), V, V(W1))
+C        *** H IS STORED IN THE END OF W AND HAS JUST BEEN OVERWRITTEN,
+C        *** SO WE MARK IT INVALID...
+         IV(H) = -IABS(H1)
+C        *** EVEN IF H WERE STORED ELSEWHERE, IT WOULD BE NECESSARY TO
+C        *** MARK INVALID THE INFORMATION DG7QTS MAY HAVE STORED IN V...
+         IV(KAGQT) = -1
+         GO TO 260
+C
+ 210  IF (H1 .GT. 0) GO TO 250
+C
+C     ***  SET H TO  D**-1 * (HC + T1*S) * D**-1.  ***
+C
+         H1 = -H1
+         IV(H) = H1
+         IV(FDH) = 0
+         J = IV(HC)
+         IF (J .GT. 0) GO TO 220
+            J = H1
+            RMAT1 = IV(RMAT)
+            CALL DL7SQR(P, V(H1), V(RMAT1))
+ 220     S1 = IV(S)
+         DO 240 I = 1, P
+              T = ONE / D(I)
+              DO 230 K = 1, I
+                   V(H1) = T * (V(J) + T1*V(S1)) / D(K)
+                   J = J + 1
+                   H1 = H1 + 1
+                   S1 = S1 + 1
+ 230               CONTINUE
+ 240          CONTINUE
+         H1 = IV(H)
+         IV(KAGQT) = -1
+C
+C  ***  COMPUTE ACTUAL GOLDFELD-QUANDT-TROTTER STEP  ***
+C
+ 250  DIG1 = IV(DIG)
+      LMAT1 = IV(LMAT)
+      CALL DG7QTS(D, V(DIG1), V(H1), IV(KAGQT), V(LMAT1), P, V(STEP1),
+     1            V, V(W1))
+      IF (IV(KALM) .GT. 0) IV(KALM) = 0
+C
+ 260  IF (IV(IRC) .NE. 6) GO TO 270
+         IF (IV(RESTOR) .NE. 2) GO TO 290
+         RSTRST = 2
+         GO TO 300
+C
+C  ***  CHECK WHETHER EVALUATING F(X0 + STEP) LOOKS WORTHWHILE  ***
+C
+ 270  IV(TOOBIG) = 0
+      IF (V(DSTNRM) .LE. ZERO) GO TO 290
+      IF (IV(IRC) .NE. 5) GO TO 280
+      IF (V(RADFAC) .LE. ONE) GO TO 280
+      IF (V(PREDUC) .GT. ONEP2 * V(FDIF)) GO TO 280
+         STEP1 = IV(STEP)
+         X01 = IV(X0)
+         CALL DV2AXY(P, V(STEP1), NEGONE, V(X01), X)
+         IF (IV(RESTOR) .NE. 2) GO TO 290
+         RSTRST = 0
+         GO TO 300
+C
+C  ***  COMPUTE F(X0 + STEP)  ***
+C
+ 280  X01 = IV(X0)
+      STEP1 = IV(STEP)
+      CALL DV2AXY(P, X, ONE, V(STEP1), V(X01))
+      IV(NFCALL) = IV(NFCALL) + 1
+      IV(1) = 1
+      GO TO 999
+C
+C. . . . . . . . . . . . .  ASSESS CANDIDATE STEP  . . . . . . . . . . .
+C
+ 290  RSTRST = 3
+ 300  X01 = IV(X0)
+      V(RELDX) = DRLDST(P, D, X, V(X01))
+      CALL DA7SST(IV, LIV, LV, V)
+      STEP1 = IV(STEP)
+      LSTGST = IV(STLSTG)
+      I = IV(RESTOR) + 1
+      GO TO (340, 310, 320, 330), I
+ 310  CALL DV7CPY(P, X, V(X01))
+      GO TO 340
+ 320   CALL DV7CPY(P, V(LSTGST), V(STEP1))
+       GO TO 340
+ 330     CALL DV7CPY(P, V(STEP1), V(LSTGST))
+         CALL DV2AXY(P, X, ONE, V(STEP1), V(X01))
+         V(RELDX) = DRLDST(P, D, X, V(X01))
+         IV(RESTOR) = RSTRST
+C
+C  ***  IF NECESSARY, SWITCH MODELS  ***
+C
+ 340  IF (IV(SWITCH) .EQ. 0) GO TO 350
+         IV(H) = -IABS(IV(H))
+         IV(SUSED) = IV(SUSED) + 2
+         L = IV(VSAVE)
+         CALL DV7CPY(NVSAVE, V, V(L))
+ 350  L = IV(IRC) - 4
+      STPMOD = IV(MODEL)
+      IF (L .GT. 0) GO TO (370,380,390,390,390,390,390,390,500,440), L
+C
+C  ***  DECIDE WHETHER TO CHANGE MODELS  ***
+C
+      E = V(PREDUC) - V(FDIF)
+      S1 = IV(S)
+      CALL DS7LVM(PS, Y, V(S1), V(STEP1))
+      STTSST = HALF * DD7TPR(PS, V(STEP1), Y)
+      IF (IV(MODEL) .EQ. 1) STTSST = -STTSST
+      IF (DABS(E + STTSST) * V(FUZZ) .GE. DABS(E)) GO TO 360
+C
+C     ***  SWITCH MODELS  ***
+C
+         IV(MODEL) = 3 - IV(MODEL)
+         IF (-2 .LT. L) GO TO 400
+              IV(H) = -IABS(IV(H))
+              IV(SUSED) = IV(SUSED) + 2
+              L = IV(VSAVE)
+              CALL DV7CPY(NVSAVE, V(L), V)
+              GO TO 160
+C
+ 360  IF (-3 .LT. L) GO TO 400
+C
+C  ***  RECOMPUTE STEP WITH NEW RADIUS  ***
+C
+ 370  V(RADIUS) = V(RADFAC) * V(DSTNRM)
+      GO TO 160
+C
+C  ***  COMPUTE STEP OF LENGTH V(LMAXS) FOR SINGULAR CONVERGENCE TEST
+C
+ 380  V(RADIUS) = V(LMAXS)
+      GO TO 200
+C
+C  ***  CONVERGENCE OR FALSE CONVERGENCE  ***
+C
+ 390  IV(CNVCOD) = L
+      IF (V(F) .GE. V(F0)) GO TO 510
+         IF (IV(XIRC) .EQ. 14) GO TO 510
+              IV(XIRC) = 14
+C
+C. . . . . . . . . . . .  PROCESS ACCEPTABLE STEP  . . . . . . . . . . .
+C
+ 400  IV(COVMAT) = 0
+      IV(REGD) = 0
+C
+C  ***  SEE WHETHER TO SET V(RADFAC) BY GRADIENT TESTS  ***
+C
+      IF (IV(IRC) .NE. 3) GO TO 430
+         STEP1 = IV(STEP)
+         TEMP1 = IV(STLSTG)
+         TEMP2 = IV(W)
+C
+C     ***  SET  TEMP1 = HESSIAN * STEP  FOR USE IN GRADIENT TESTS  ***
+C
+         HC1 = IV(HC)
+         IF (HC1 .LE. 0) GO TO 410
+              CALL DS7LVM(P, V(TEMP1), V(HC1), V(STEP1))
+              GO TO 420
+ 410     RMAT1 = IV(RMAT)
+         CALL DL7TVM(P, V(TEMP1), V(RMAT1), V(STEP1))
+         CALL DL7VML(P, V(TEMP1), V(RMAT1), V(TEMP1))
+C
+ 420     IF (STPMOD .EQ. 1) GO TO 430
+              S1 = IV(S)
+              CALL DS7LVM(PS, V(TEMP2), V(S1), V(STEP1))
+              CALL DV2AXY(PS, V(TEMP1), ONE, V(TEMP2), V(TEMP1))
+C
+C  ***  SAVE OLD GRADIENT AND COMPUTE NEW ONE  ***
+C
+ 430  IV(NGCALL) = IV(NGCALL) + 1
+      G01 = IV(W)
+      CALL DV7CPY(P, V(G01), G)
+      IV(1) = 2
+      IV(TOOBIG) = 0
+      GO TO 999
+C
+C  ***  INITIALIZATIONS -- G0 = G - G0, ETC.  ***
+C
+ 440  G01 = IV(W)
+      CALL DV2AXY(P, V(G01), NEGONE, V(G01), G)
+      STEP1 = IV(STEP)
+      TEMP1 = IV(STLSTG)
+      TEMP2 = IV(W)
+      IF (IV(IRC) .NE. 3) GO TO 470
+C
+C  ***  SET V(RADFAC) BY GRADIENT TESTS  ***
+C
+C     ***  SET  TEMP1 = D**-1 * (HESSIAN * STEP  +  (G(X0) - G(X)))  ***
+C
+         K = TEMP1
+         L = G01
+         DO 450 I = 1, P
+              V(K) = (V(K) - V(L)) / D(I)
+              K = K + 1
+              L = L + 1
+ 450          CONTINUE
+C
+C        ***  DO GRADIENT TESTS  ***
+C
+         IF (DV2NRM(P, V(TEMP1)) .LE. V(DGNORM) * V(TUNER4))  GO TO 460
+              IF (DD7TPR(P, G, V(STEP1))
+     1                  .GE. V(GTSTEP) * V(TUNER5))  GO TO 470
+ 460               V(RADFAC) = V(INCFAC)
+C
+C  ***  COMPUTE Y VECTOR NEEDED FOR UPDATING S  ***
+C
+ 470  CALL DV2AXY(PS, Y, NEGONE, Y, G)
+C
+C  ***  DETERMINE SIZING FACTOR V(SIZE)  ***
+C
+C     ***  SET TEMP1 = S * STEP  ***
+      S1 = IV(S)
+      CALL DS7LVM(PS, V(TEMP1), V(S1), V(STEP1))
+C
+      T1 = DABS(DD7TPR(PS, V(STEP1), V(TEMP1)))
+      T = DABS(DD7TPR(PS, V(STEP1), Y))
+      V(SIZE) = ONE
+      IF (T .LT. T1) V(SIZE) = T / T1
+C
+C  ***  SET G0 TO WCHMTD CHOICE OF FLETCHER AND AL-BAALI  ***
+C
+      HC1 = IV(HC)
+      IF (HC1 .LE. 0) GO TO 480
+         CALL DS7LVM(PS, V(G01), V(HC1), V(STEP1))
+         GO TO 490
+C
+ 480  RMAT1 = IV(RMAT)
+      CALL DL7TVM(PS, V(G01), V(RMAT1), V(STEP1))
+      CALL DL7VML(PS, V(G01), V(RMAT1), V(G01))
+C
+ 490  CALL DV2AXY(PS, V(G01), ONE, Y, V(G01))
+C
+C  ***  UPDATE S  ***
+C
+      CALL DS7LUP(V(S1), V(COSMIN), PS, V(SIZE), V(STEP1), V(TEMP1),
+     1            V(TEMP2), V(G01), V(WSCALE), Y)
+      IV(1) = 2
+      GO TO 110
+C
+C. . . . . . . . . . . . . .  MISC. DETAILS  . . . . . . . . . . . . . .
+C
+C  ***  BAD PARAMETERS TO ASSESS  ***
+C
+ 500  IV(1) = 64
+      GO TO 999
+C
+C
+C  ***  CONVERGENCE OBTAINED -- SEE WHETHER TO COMPUTE COVARIANCE  ***
+C
+ 510  IF (IV(RDREQ) .EQ. 0) GO TO 600
+      IF (IV(FDH) .NE. 0) GO TO 600
+      IF (IV(CNVCOD) .GE. 7) GO TO 600
+      IF (IV(REGD) .GT. 0) GO TO 600
+      IF (IV(COVMAT) .GT. 0) GO TO 600
+      IF (IABS(IV(COVREQ)) .GE. 3) GO TO 560
+      IF (IV(RESTOR) .EQ. 0) IV(RESTOR) = 2
+      GO TO 530
+C
+C  ***  COMPUTE FINITE-DIFFERENCE HESSIAN FOR COMPUTING COVARIANCE  ***
+C
+ 520  IV(RESTOR) = 0
+ 530  CALL DF7HES(D, G, I, IV, LIV, LV, P, V, X)
+      GO TO (540, 550, 580), I
+ 540  IV(NFCOV) = IV(NFCOV) + 1
+      IV(NFCALL) = IV(NFCALL) + 1
+      IV(1) = 1
+      GO TO 999
+C
+ 550  IV(NGCOV) = IV(NGCOV) + 1
+      IV(NGCALL) = IV(NGCALL) + 1
+      IV(NFGCAL) = IV(NFCALL) + IV(NGCOV)
+      IV(1) = 2
+      GO TO 999
+C
+ 560  H1 = IABS(IV(H))
+      IV(H) = -H1
+      PP1O2 = P * (P + 1) / 2
+      RMAT1 = IV(RMAT)
+      IF (RMAT1 .LE. 0) GO TO 570
+           LMAT1 = IV(LMAT)
+           CALL DV7CPY(PP1O2, V(LMAT1), V(RMAT1))
+           V(RCOND) = ZERO
+           GO TO 590
+ 570  HC1 = IV(HC)
+      IV(FDH) = H1
+      CALL DV7CPY(P*(P+1)/2, V(H1), V(HC1))
+C
+C  ***  COMPUTE CHOLESKY FACTOR OF FINITE-DIFFERENCE HESSIAN
+C  ***  FOR USE IN CALLER*S COVARIANCE CALCULATION...
+C
+ 580  LMAT1 = IV(LMAT)
+      H1 = IV(FDH)
+      IF (H1 .LE. 0) GO TO 600
+      IF (IV(CNVCOD) .EQ. 70) GO TO 80
+      CALL DL7SRT(1, P, V(LMAT1), V(H1), I)
+      IV(FDH) = -1
+      V(RCOND) = ZERO
+      IF (I .NE. 0) GO TO 600
+C
+ 590  IV(FDH) = -1
+      STEP1 = IV(STEP)
+      T = DL7SVN(P, V(LMAT1), V(STEP1), V(STEP1))
+      IF (T .LE. ZERO) GO TO 600
+      T = T / DL7SVX(P, V(LMAT1), V(STEP1), V(STEP1))
+      IF (T .GT. DR7MDC(4)) IV(FDH) = H1
+      V(RCOND) = T
+C
+ 600  IV(MODE) = 0
+      IV(1) = IV(CNVCOD)
+      IV(CNVCOD) = 0
+      GO TO 999
+C
+C  ***  SPECIAL RETURN FOR MISSING HESSIAN INFORMATION -- BOTH
+C  ***  IV(HC) .LE. 0 AND IV(RMAT) .LE. 0
+C
+ 610  IV(1) = 1400
+C
+ 999  RETURN
+C
+C  ***  LAST LINE OF DG7LIT FOLLOWS  ***
+      END
+      SUBROUTINE DL7MSB(B, D, G, IERR, IPIV, IPIV1, IPIV2, KA, LMAT,
+     1                  LV, P, P0, PC, QTR, RMAT, STEP, TD, TG, V,
+     2                  W, WLM, X, X0)
+C
+C  ***  COMPUTE HEURISTIC BOUNDED NEWTON STEP  ***
+C
+      INTEGER IERR, KA, LV, P, P0, PC
+      INTEGER IPIV(P), IPIV1(P), IPIV2(P)
+      DOUBLE PRECISION B(2,P), D(P), G(P), LMAT(*), QTR(P), RMAT(*),
+     1                 STEP(P,3), TD(P), TG(P), V(LV), W(P), WLM(*),
+     2                 X0(P), X(P)
+C     DIMENSION LMAT(P*(P+1)/2), RMAT(P*(P+1)/2), WLM(P*(P+5)/2 + 4)
+C
+      DOUBLE PRECISION DD7TPR
+      EXTERNAL DD7MLP, DD7TPR, DL7MST, DL7TVM, DQ7RSH, DS7BQN,
+     1        DV2AXY,DV7CPY, DV7IPR, DV7SCP, DV7VMP
+C
+C  ***  LOCAL VARIABLES  ***
+C
+      INTEGER I, J, K, K0, KB, KINIT, L, NS, P1, P10, P11
+      DOUBLE PRECISION DS0, NRED, PRED, RAD
+      DOUBLE PRECISION ONE, ZERO
+C
+C  ***  V SUBSCRIPTS  ***
+C
+      INTEGER DST0, DSTNRM, GTSTEP, NREDUC, PREDUC, RADIUS
+C
+      PARAMETER (DST0=3, DSTNRM=2, GTSTEP=4, NREDUC=6, PREDUC=7,
+     1           RADIUS=8)
+      DATA ONE/1.D+0/, ZERO/0.D+0/
+C
+C+++++++++++++++++++++++++++++++  BODY  ++++++++++++++++++++++++++++++++
+C
+      P1 = PC
+      IF (KA .LT. 0) GO TO 10
+         NRED = V(NREDUC)
+         DS0 = V(DST0)
+         GO TO 20
+ 10   P0 = 0
+      KA = -1
+C
+ 20   KINIT = -1
+      IF (P0 .EQ. P1) KINIT = KA
+      CALL DV7CPY(P, X, X0)
+      CALL DV7CPY(P, TD, D)
+C     *** USE STEP(1,3) AS TEMP. COPY OF QTR ***
+      CALL DV7CPY(P, STEP(1,3), QTR)
+      CALL DV7IPR(P, IPIV, TD)
+      PRED = ZERO
+      RAD = V(RADIUS)
+      KB = -1
+      V(DSTNRM) = ZERO
+      IF (P1 .GT. 0) GO TO 30
+         NRED = ZERO
+         DS0 = ZERO
+         CALL DV7SCP(P, STEP, ZERO)
+         GO TO 90
+C
+ 30   CALL DV7VMP(P, TG, G, D, -1)
+      CALL DV7IPR(P, IPIV, TG)
+      P10 = P1
+ 40   K = KINIT
+      KINIT = -1
+      V(RADIUS) = RAD - V(DSTNRM)
+      CALL DV7VMP(P1, TG, TG, TD, 1)
+      DO 50 I = 1, P1
+ 50      IPIV1(I) = I
+      K0 = MAX0(0, K)
+      CALL DL7MST(TD, TG, IERR, IPIV1, K, P1, STEP(1,3), RMAT, STEP,
+     1            V, WLM)
+      CALL DV7VMP(P1, TG, TG, TD, -1)
+      P0 = P1
+      IF (KA .GE. 0) GO TO 60
+         NRED = V(NREDUC)
+         DS0 = V(DST0)
+C
+ 60   KA = K
+      V(RADIUS) = RAD
+      L = P1 + 5
+      IF (K .LE. K0) CALL DD7MLP(P1, LMAT, TD, RMAT, -1)
+      IF (K .GT. K0) CALL DD7MLP(P1, LMAT, TD, WLM(L), -1)
+      CALL DS7BQN(B, D, STEP(1,2), IPIV, IPIV1, IPIV2, KB, LMAT,
+     1            LV, NS, P, P1, STEP, TD, TG, V, W, X, X0)
+      PRED = PRED + V(PREDUC)
+      IF (NS .EQ. 0) GO TO 80
+      P0 = 0
+C
+C  ***  UPDATE RMAT AND QTR  ***
+C
+      P11 = P1 + 1
+      L = P10 + P11
+      DO 70 K = P11, P10
+         J = L - K
+         I = IPIV2(J)
+         IF (I .LT. J) CALL DQ7RSH(I, J, .TRUE., QTR, RMAT, W)
+ 70      CONTINUE
+C
+ 80   IF (KB .GT. 0) GO TO 90
+C
+C  ***  UPDATE LOCAL COPY OF QTR  ***
+C
+      CALL DV7VMP(P10, W, STEP(1,2), TD, -1)
+      CALL DL7TVM(P10, W, LMAT, W)
+      CALL DV2AXY(P10, STEP(1,3), ONE, W, QTR)
+      GO TO 40
+C
+ 90   V(DST0) = DS0
+      V(NREDUC) = NRED
+      V(PREDUC) = PRED
+      V(GTSTEP) = DD7TPR(P, G, STEP)
+C
+      RETURN
+C  ***  LAST LINE OF DL7MSB FOLLOWS  ***
+      END
+      SUBROUTINE DN2LRD(DR, IV, L, LH, LIV, LV, ND, NN, P, R, RD, V)
+C
+C  ***  COMPUTE REGRESSION DIAGNOSTIC AND DEFAULT COVARIANCE MATRIX FOR
+C        DRN2G  ***
+C
+C  ***  PARAMETERS  ***
+C
+      INTEGER LH, LIV, LV, ND, NN, P
+      INTEGER IV(LIV)
+      DOUBLE PRECISION DR(ND,P), L(LH), R(NN), RD(NN), V(LV)
+C
+C  ***  CODED BY DAVID M. GAY (WINTER 1982, FALL 1983)  ***
+C
+C  ***  EXTERNAL FUNCTIONS AND SUBROUTINES  ***
+C
+      DOUBLE PRECISION DD7TPR
+      EXTERNAL DD7TPR, DL7ITV, DL7IVM,DO7PRD, DV7SCP
+C
+C  ***  LOCAL VARIABLES  ***
+C
+      INTEGER COV, I, J, M, STEP1
+      DOUBLE PRECISION A, FF, S, T
+C
+C  ***  CONSTANTS  ***
+C
+      DOUBLE PRECISION NEGONE, ONE, ONEV(1), ZERO
+C
+C  ***  INTRINSIC FUNCTIONS  ***
+C/+
+      DOUBLE PRECISION DSQRT
+C/
+C
+C  ***  IV AND V SUBSCRIPTS  ***
+C
+      INTEGER F, H, MODE, RDREQ, STEP
+      PARAMETER (F=10, H=56, MODE=35, RDREQ=57, STEP=40)
+      PARAMETER (NEGONE=-1.D+0, ONE=1.D+0, ZERO=0.D+0)
+      DATA ONEV(1)/1.D+0/
+C
+C++++++++++++++++++++++++++++++++  BODY  +++++++++++++++++++++++++++++++
+C
+      STEP1 = IV(STEP)
+      I = IV(RDREQ)
+      IF (I .LE. 0) GO TO 999
+      IF (MOD(I,4) .LT. 2) GO TO 30
+      FF = ONE
+      IF (V(F) .NE. ZERO) FF = ONE / DSQRT(DABS(V(F)))
+      CALL DV7SCP(NN, RD, NEGONE)
+      DO 20 I = 1, NN
+         A = R(I)**2
+         M = STEP1
+         DO 10 J = 1, P
+            V(M) = DR(I,J)
+            M = M + 1
+ 10         CONTINUE
+         CALL DL7IVM(P, V(STEP1), L, V(STEP1))
+         S = DD7TPR(P, V(STEP1), V(STEP1))
+         T = ONE - S
+         IF (T .LE. ZERO) GO TO 20
+         A = A * S / T
+         RD(I) = DSQRT(A) * FF
+ 20      CONTINUE
+C
+ 30   IF (IV(MODE) - P .LT. 2) GO TO 999
+C
+C  ***  COMPUTE DEFAULT COVARIANCE MATRIX  ***
+C
+      COV = IABS(IV(H))
+      DO 50 I = 1, NN
+         M = STEP1
+         DO 40 J = 1, P
+            V(M) = DR(I,J)
+            M = M + 1
+ 40         CONTINUE
+         CALL DL7IVM(P, V(STEP1), L, V(STEP1))
+         CALL DL7ITV(P, V(STEP1), L, V(STEP1))
+         CALL DO7PRD(1, LH, P, V(COV), ONEV, V(STEP1), V(STEP1))
+ 50      CONTINUE
+C
+ 999  RETURN
+C  ***  LAST LINE OF DN2LRD FOLLOWS  ***
+      END
+      SUBROUTINE DR7TVM(N, P, Y, D, U, X)
+C
+C  ***  SET Y TO R*X, WHERE R IS THE UPPER TRIANGULAR MATRIX WHOSE
+C  ***  DIAGONAL IS IN D AND WHOSE STRICT UPPER TRIANGLE IS IN U.
+C
+C  ***  X AND Y MAY SHARE STORAGE.
+C
+      INTEGER N, P
+      DOUBLE PRECISION Y(P), D(P), U(N,P), X(P)
+C
+      DOUBLE PRECISION DD7TPR
+      EXTERNAL DD7TPR
+C
+C  ***  LOCAL VARIABLES  ***
+C
+      INTEGER I, II, PL, PP1
+      DOUBLE PRECISION T
+C
+C  ***  BODY  ***
+C
+      PL = MIN0(N, P)
+      PP1 = PL + 1
+      DO 10 II = 1, PL
+         I = PP1 - II
+         T = X(I) * D(I)
+         IF (I .GT. 1) T = T + DD7TPR(I-1, U(1,I), X)
+         Y(I) = T
+ 10      CONTINUE
+      RETURN
+C  ***  LAST LINE OF DR7TVM FOLLOWS  ***
+      END
+      SUBROUTINE DQ7RAD(N, NN, P, QTR, QTRSET, RMAT, W, Y)
+C
+C  ***  ADD ROWS W TO QR FACTORIZATION WITH R MATRIX RMAT AND
+C  ***  Q**T * RESIDUAL = QTR.  Y = NEW COMPONENTS OF RESIDUAL
+C  ***  CORRESPONDING TO W.  QTR, Y REFERENCED ONLY IF QTRSET = .TRUE.
+C
+      LOGICAL QTRSET
+      INTEGER N, NN, P
+      DOUBLE PRECISION QTR(P), RMAT(*), W(NN,P), Y(N)
+C     DIMENSION RMAT(P*(P+1)/2)
+C/+
+      DOUBLE PRECISION DSQRT
+C/
+      DOUBLE PRECISION DD7TPR, DR7MDC, DV2NRM
+      EXTERNAL DD7TPR, DR7MDC,DV2AXY, DV7SCL, DV2NRM
+C
+C  ***  LOCAL VARIABLES  ***
+C
+      INTEGER I, II, IJ, IP1, J, K, NK
+      DOUBLE PRECISION ARI, QRI, RI, S, T, WI
+      DOUBLE PRECISION BIG, BIGRT, ONE, TINY, TINYRT, ZERO
+      SAVE BIGRT, TINY, TINYRT
+      DATA BIG/-1.D+0/, BIGRT/-1.D+0/, ONE/1.D+0/, TINY/0.D+0/,
+     1     TINYRT/0.D+0/, ZERO/0.D+0/
+C
+C------------------------------ BODY -----------------------------------
+C
+      IF (TINY .GT. ZERO) GO TO 10
+         TINY = DR7MDC(1)
+         BIG = DR7MDC(6)
+         IF (TINY*BIG .LT. ONE) TINY = ONE / BIG
+ 10   K = 1
+      NK = N
+      II = 0
+      DO 180 I = 1, P
+         II = II + I
+         IP1 = I + 1
+         IJ = II + I
+         IF (NK .LE. 1) T = DABS(W(K,I))
+         IF (NK .GT. 1) T = DV2NRM(NK, W(K,I))
+         IF (T .LT. TINY) GOTO  180
+         RI = RMAT(II)
+         IF (RI .NE. ZERO) GO TO 100
+            IF (NK .GT. 1) GO TO 30
+               IJ = II
+               DO 20 J = I, P
+                  RMAT(IJ) = W(K,J)
+                  IJ = IJ + J
+ 20               CONTINUE
+               IF (QTRSET) QTR(I) = Y(K)
+               W(K,I) = ZERO
+               GO TO 999
+ 30         WI = W(K,I)
+            IF (BIGRT .GT. ZERO) GO TO 40
+               BIGRT = DR7MDC(5)
+               TINYRT = DR7MDC(2)
+ 40         IF (T .LE. TINYRT) GO TO 50
+            IF (T .GE. BIGRT) GO TO 50
+               IF (WI .LT. ZERO) T = -T
+               WI = WI + T
+               S = DSQRT(T * WI)
+               GO TO 70
+ 50         S = DSQRT(T)
+            IF (WI .LT. ZERO) GO TO 60
+               WI = WI + T
+               S = S * DSQRT(WI)
+               GO TO 70
+ 60         T = -T
+            WI = WI + T
+            S = S * DSQRT(-WI)
+ 70         W(K,I) = WI
+            CALL DV7SCL(NK, W(K,I), ONE/S, W(K,I))
+            RMAT(II) = -T
+            IF (.NOT. QTRSET) GO TO 80
+            CALL DV2AXY(NK, Y(K), -DD7TPR(NK,Y(K),W(K,I)), W(K,I), Y(K))
+            QTR(I) = Y(K)
+ 80         IF (IP1 .GT. P) GO TO 999
+            DO 90 J = IP1, P
+               CALL DV2AXY(NK, W(K,J), -DD7TPR(NK,W(K,J),W(K,I)),
+     1                    W(K,I), W(K,J))
+               RMAT(IJ) = W(K,J)
+               IJ = IJ + J
+ 90            CONTINUE
+            IF (NK .LE. 1) GO TO 999
+            K = K + 1
+            NK = NK - 1
+            GO TO 180
+C
+ 100     ARI = DABS(RI)
+         IF (ARI .GT. T) GO TO 110
+            T = T * DSQRT(ONE + (ARI/T)**2)
+            GO TO 120
+ 110     T = ARI * DSQRT(ONE + (T/ARI)**2)
+ 120     IF (RI .LT. ZERO) T = -T
+         RI = RI + T
+         RMAT(II) = -T
+         S = -RI / T
+         IF (NK .LE. 1) GO TO 150
+         CALL DV7SCL(NK, W(K,I), ONE/RI, W(K,I))
+         IF (.NOT. QTRSET) GO TO 130
+            QRI = QTR(I)
+            T = S * ( QRI  +  DD7TPR(NK, Y(K), W(K,I)) )
+            QTR(I) = QRI + T
+ 130     IF (IP1 .GT. P) GO TO 999
+         IF (QTRSET) CALL DV2AXY(NK, Y(K), T, W(K,I), Y(K))
+         DO 140 J = IP1, P
+            RI = RMAT(IJ)
+            T = S * ( RI  +  DD7TPR(NK, W(K,J), W(K,I)) )
+            CALL DV2AXY(NK, W(K,J), T, W(K,I), W(K,J))
+            RMAT(IJ) = RI + T
+            IJ = IJ + J
+ 140        CONTINUE
+         GO TO 180
+C
+ 150     WI = W(K,I) / RI
+         W(K,I) = WI
+         IF (.NOT. QTRSET) GO TO 160
+            QRI = QTR(I)
+            T = S * ( QRI + Y(K)*WI )
+            QTR(I) = QRI + T
+ 160     IF (IP1 .GT. P) GO TO 999
+         IF (QTRSET) Y(K) = T*WI + Y(K)
+         DO 170 J = IP1, P
+            RI = RMAT(IJ)
+            T = S * (RI + W(K,J)*WI)
+            W(K,J) = W(K,J) + T*WI
+            RMAT(IJ) = RI + T
+            IJ = IJ + J
+ 170        CONTINUE
+ 180     CONTINUE
+C
+ 999  RETURN
+C  ***  LAST LINE OF DQ7RAD FOLLOWS  ***
+      END
+      SUBROUTINE DF7HES(D, G, IRT, IV, LIV, LV, P, V, X)
+C
+C  ***  COMPUTE FINITE-DIFFERENCE HESSIAN, STORE IT IN V STARTING
+C  ***  AT V(IV(FDH)) = V(-IV(H)).
+C
+C  ***  IF IV(COVREQ) .GE. 0 THEN DF7HES USES GRADIENT DIFFERENCES,
+C  ***  OTHERWISE FUNCTION DIFFERENCES.  STORAGE IN V IS AS IN DG7LIT.
+C
+C IRT VALUES...
+C     1 = COMPUTE FUNCTION VALUE, I.E., V(F).
+C     2 = COMPUTE G.
+C     3 = DONE.
+C
+C
+C  ***  PARAMETER DECLARATIONS  ***
+C
+      INTEGER IRT, LIV, LV, P
+      INTEGER IV(LIV)
+      DOUBLE PRECISION D(P), G(P), V(LV), X(P)
+C
+C  ***  LOCAL VARIABLES  ***
+C
+      INTEGER GSAVE1, HES, HMI, HPI, HPM, I, K, KIND, L, M, MM1, MM1O2,
+     1        PP1O2, STPI, STPM, STP0
+      DOUBLE PRECISION DEL, HALF, NEGPT5, ONE, TWO, ZERO
+C
+C  ***  EXTERNAL SUBROUTINES  ***
+C
+      EXTERNAL DV7CPY
+C
+C DV7CPY.... COPY ONE VECTOR TO ANOTHER.
+C
+C  ***  SUBSCRIPTS FOR IV AND V  ***
+C
+      INTEGER COVREQ, DELTA, DELTA0, DLTFDC, F, FDH, FX, H, KAGQT, MODE,
+     1        NFGCAL, SAVEI, SWITCH, TOOBIG, W, XMSAVE
+C
+      PARAMETER (HALF=0.5D+0, NEGPT5=-0.5D+0, ONE=1.D+0, TWO=2.D+0,
+     1     ZERO=0.D+0)
+C
+      PARAMETER (COVREQ=15, DELTA=52, DELTA0=44, DLTFDC=42, F=10,
+     1           FDH=74, FX=53, H=56, KAGQT=33, MODE=35, NFGCAL=7,
+     2           SAVEI=63, SWITCH=12, TOOBIG=2, W=65, XMSAVE=51)
+C
+C+++++++++++++++++++++++++++++++  BODY  ++++++++++++++++++++++++++++++++
+C
+      IRT = 4
+      KIND = IV(COVREQ)
+      M = IV(MODE)
+      IF (M .GT. 0) GO TO 10
+         IV(H) = -IABS(IV(H))
+         IV(FDH) = 0
+         IV(KAGQT) = -1
+         V(FX) = V(F)
+ 10   IF (M .GT. P) GO TO 999
+      IF (KIND .LT. 0) GO TO 110
+C
+C  ***  COMPUTE FINITE-DIFFERENCE HESSIAN USING BOTH FUNCTION AND
+C  ***  GRADIENT VALUES.
+C
+      GSAVE1 = IV(W) + P
+      IF (M .GT. 0) GO TO 20
+C        ***  FIRST CALL ON DF7HES.  SET GSAVE = G, TAKE FIRST STEP  ***
+         CALL DV7CPY(P, V(GSAVE1), G)
+         IV(SWITCH) = IV(NFGCAL)
+         GO TO 90
+C
+ 20   DEL = V(DELTA)
+      X(M) = V(XMSAVE)
+      IF (IV(TOOBIG) .EQ. 0) GO TO 40
+C
+C     ***  HANDLE OVERSIZE V(DELTA)  ***
+C
+         IF (DEL*X(M) .GT. ZERO) GO TO 30
+C             ***  WE ALREADY TRIED SHRINKING V(DELTA), SO QUIT  ***
+              IV(FDH) = -2
+              GO TO 220
+C
+C        ***  TRY SHRINKING V(DELTA)  ***
+ 30      DEL = NEGPT5 * DEL
+         GO TO 100
+C
+ 40   HES = -IV(H)
+C
+C  ***  SET  G = (G - GSAVE)/DEL  ***
+C
+      DO 50 I = 1, P
+         G(I) = (G(I) - V(GSAVE1)) / DEL
+         GSAVE1 = GSAVE1 + 1
+ 50      CONTINUE
+C
+C  ***  ADD G AS NEW COL. TO FINITE-DIFF. HESSIAN MATRIX  ***
+C
+      K = HES + M*(M-1)/2
+      L = K + M - 2
+      IF (M .EQ. 1) GO TO 70
+C
+C  ***  SET  H(I,M) = 0.5 * (H(I,M) + G(I))  FOR I = 1 TO M-1  ***
+C
+      MM1 = M - 1
+      DO 60 I = 1, MM1
+         V(K) = HALF * (V(K) + G(I))
+         K = K + 1
+ 60      CONTINUE
+C
+C  ***  ADD  H(I,M) = G(I)  FOR I = M TO P  ***
+C
+ 70   L = L + 1
+      DO 80 I = M, P
+         V(L) = G(I)
+         L = L + I
+ 80      CONTINUE
+C
+ 90   M = M + 1
+      IV(MODE) = M
+      IF (M .GT. P) GO TO 210
+C
+C  ***  CHOOSE NEXT FINITE-DIFFERENCE STEP, RETURN TO GET G THERE  ***
+C
+      DEL = V(DELTA0) * DMAX1(ONE/D(M), DABS(X(M)))
+      IF (X(M) .LT. ZERO) DEL = -DEL
+      V(XMSAVE) = X(M)
+ 100  X(M) = X(M) + DEL
+      V(DELTA) = DEL
+      IRT = 2
+      GO TO 999
+C
+C  ***  COMPUTE FINITE-DIFFERENCE HESSIAN USING FUNCTION VALUES ONLY.
+C
+ 110  STP0 = IV(W) + P - 1
+      MM1 = M - 1
+      MM1O2 = M*MM1/2
+      IF (M .GT. 0) GO TO 120
+C        ***  FIRST CALL ON DF7HES.  ***
+         IV(SAVEI) = 0
+         GO TO 200
+C
+ 120  I = IV(SAVEI)
+      HES = -IV(H)
+      IF (I .GT. 0) GO TO 180
+      IF (IV(TOOBIG) .EQ. 0) GO TO 140
+C
+C     ***  HANDLE OVERSIZE STEP  ***
+C
+         STPM = STP0 + M
+         DEL = V(STPM)
+         IF (DEL*X(XMSAVE) .GT. ZERO) GO TO 130
+C             ***  WE ALREADY TRIED SHRINKING THE STEP, SO QUIT  ***
+              IV(FDH) = -2
+              GO TO 220
+C
+C        ***  TRY SHRINKING THE STEP  ***
+ 130     DEL = NEGPT5 * DEL
+         X(M) = X(XMSAVE) + DEL
+         V(STPM) = DEL
+         IRT = 1
+         GO TO 999
+C
+C  ***  SAVE F(X + STP(M)*E(M)) IN H(P,M)  ***
+C
+ 140  PP1O2 = P * (P-1) / 2
+      HPM = HES + PP1O2 + MM1
+      V(HPM) = V(F)
+C
+C  ***  START COMPUTING ROW M OF THE FINITE-DIFFERENCE HESSIAN H.  ***
+C
+      HMI = HES + MM1O2
+      IF (MM1 .EQ. 0) GO TO 160
+      HPI = HES + PP1O2
+      DO 150 I = 1, MM1
+         V(HMI) = V(FX) - (V(F) + V(HPI))
+         HMI = HMI + 1
+         HPI = HPI + 1
+ 150     CONTINUE
+ 160  V(HMI) = V(F) - TWO*V(FX)
+C
+C  ***  COMPUTE FUNCTION VALUES NEEDED TO COMPLETE ROW M OF H.  ***
+C
+      I = 1
+C
+ 170  IV(SAVEI) = I
+      STPI = STP0 + I
+      V(DELTA) = X(I)
+      X(I) = X(I) + V(STPI)
+      IF (I .EQ. M) X(I) = V(XMSAVE) - V(STPI)
+      IRT = 1
+      GO TO 999
+C
+ 180  X(I) = V(DELTA)
+      IF (IV(TOOBIG) .EQ. 0) GO TO 190
+C        ***  PUNT IN THE EVENT OF AN OVERSIZE STEP  ***
+         IV(FDH) = -2
+         GO TO 220
+C
+C  ***  FINISH COMPUTING H(M,I)  ***
+C
+ 190  STPI = STP0 + I
+      HMI = HES + MM1O2 + I - 1
+      STPM = STP0 + M
+      V(HMI) = (V(HMI) + V(F)) / (V(STPI)*V(STPM))
+      I = I + 1
+      IF (I .LE. M) GO TO 170
+      IV(SAVEI) = 0
+      X(M) = V(XMSAVE)
+C
+ 200  M = M + 1
+      IV(MODE) = M
+      IF (M .GT. P) GO TO 210
+C
+C  ***  PREPARE TO COMPUTE ROW M OF THE FINITE-DIFFERENCE HESSIAN H.
+C  ***  COMPUTE M-TH STEP SIZE STP(M), THEN RETURN TO OBTAIN
+C  ***  F(X + STP(M)*E(M)), WHERE E(M) = M-TH STD. UNIT VECTOR.
+C
+      DEL = V(DLTFDC) * DMAX1(ONE/D(M), DABS(X(M)))
+      IF (X(M) .LT. ZERO) DEL = -DEL
+      V(XMSAVE) = X(M)
+      X(M) = X(M) + DEL
+      STPM = STP0 + M
+      V(STPM) = DEL
+      IRT = 1
+      GO TO 999
+C
+C  ***  RESTORE V(F), ETC.  ***
+C
+ 210  IV(FDH) = HES
+ 220  V(F) = V(FX)
+      IRT = 3
+      IF (KIND .LT. 0) GO TO 999
+         IV(NFGCAL) = IV(SWITCH)
+         GSAVE1 = IV(W) + P
+         CALL DV7CPY(P, G, V(GSAVE1))
+         GO TO 999
+C
+ 999  RETURN
+C  ***  LAST CARD OF DF7HES FOLLOWS  ***
+      END
+      SUBROUTINE  DRNSG(A, ALF, C, DA, IN, IV, L, L1, LA, LIV, LV,
+     1                  N, NDA, P, V, Y)
+C
+C  ***  ITERATION DRIVER FOR SEPARABLE NONLINEAR LEAST SQUARES.
+C
+C  ***  PARAMETER DECLARATIONS  ***
+C
+      INTEGER L, L1, LA, LIV, LV, N, NDA, P
+      INTEGER IN(2,NDA), IV(LIV)
+C     DIMENSION UIPARM(*)
+      DOUBLE PRECISION A(LA,L1), ALF(P), C(L), DA(LA,NDA), V(LV), Y(N)
+C
+C  ***  PURPOSE  ***
+C
+C GIVEN A SET OF N OBSERVATIONS Y(1)....Y(N) OF A DEPENDENT VARIABLE
+C T(1)...T(N),  DRNSG ATTEMPTS TO COMPUTE A LEAST SQUARES FIT
+C TO A FUNCTION  ETA  (THE MODEL) WHICH IS A LINEAR COMBINATION
+C
+C                  L
+C ETA(C,ALF,T) =  SUM C * PHI(ALF,T) +PHI   (ALF,T)
+C                 J=1  J     J           L+1
+C
+C OF NONLINEAR FUNCTIONS PHI(J) DEPENDENT ON T AND ALF(1),...,ALF(P)
+C (.E.G. A SUM OF EXPONENTIALS OR GAUSSIANS).  THAT IS, IT DETERMINES
+C NONLINEAR PARAMETERS ALF WHICH MINIMIZE
+C
+C                   2    N                      2
+C     NORM(RESIDUAL)  = SUM  (Y - ETA(C,ALF,T )).
+C                       I=1    I             I
+C
+C THE (L+1)ST TERM IS OPTIONAL.
+C
+C
+C  ***  PARAMETERS  ***
+C
+C      A (IN)  MATRIX PHI(ALF,T) OF THE MODEL.
+C    ALF (I/O) NONLINEAR PARAMETERS.
+C                 INPUT = INITIAL GUESS,
+C                 OUTPUT = BEST ESTIMATE FOUND.
+C      C (OUT) LINEAR PARAMETERS (ESTIMATED).
+C     DA (IN)  DERIVATIVES OF COLUMNS OF A WITH RESPECT TO COMPONENTS
+C                 OF ALF, AS SPECIFIED BY THE IN ARRAY...
+C     IN (IN)  WHEN  DRNSG IS CALLED WITH IV(1) = 2 OR -2, THEN FOR
+C                 I = 1(1)NDA, COLUMN I OF DA IS THE PARTIAL
+C                 DERIVATIVE WITH RESPECT TO ALF(IN(1,I)) OF COLUMN
+C                 IN(2,I) OF A, UNLESS IV(1,I) IS NOT POSITIVE (IN
+C                 WHICH CASE COLUMN I OF DA IS IGNORED.  IV(1) = -2
+C                 MEANS THERE ARE MORE COLUMNS OF DA TO COME AND
+C                  DRNSG SHOULD RETURN FOR THEM.
+C     IV (I/O) INTEGER PARAMETER AND SCRATCH VECTOR.   DRNSG RETURNS
+C                 WITH IV(1) = 1 WHEN IT WANTS A TO BE EVALUATED AT
+C                 ALF AND WITH IV(1) = 2 WHEN IT WANTS DA TO BE
+C                 EVALUATED AT ALF.  WHEN CALLED WITH IV(1) = -2
+C                 (AFTER A RETURN WITH IV(1) = 2),  DRNSG RETURNS
+C                 WITH IV(1) = -2 TO GET MORE COLUMNS OF DA.
+C      L (IN)  NUMBER OF LINEAR PARAMETERS TO BE ESTIMATED.
+C     L1 (IN)  L+1 IF PHI(L+1) IS IN THE MODEL, L IF NOT.
+C     LA (IN)  LEAD DIMENSION OF A.  MUST BE AT LEAST N.
+C    LIV (IN)  LENGTH OF IV.  MUST BE AT LEAST 110 + L + P.
+C     LV (IN)  LENGTH OF V.  MUST BE AT LEAST
+C                 105 + 2*N + JLEN + L*(L+3)/2 + P*(2*P + 17),
+C                 WHERE  JLEN = (L+P)*(N+L+P+1),  UNLESS NEITHER A
+C                 COVARIANCE MATRIX NOR REGRESSION DIAGNOSTICS ARE
+C                 REQUESTED, IN WHICH CASE  JLEN = N*P.
+C      N (IN)  NUMBER OF OBSERVATIONS.
+C    NDA (IN)  NUMBER OF COLUMNS IN DA AND IN.
+C      P (IN)  NUMBER OF NONLINEAR PARAMETERS TO BE ESTIMATED.
+C      V (I/O) FLOATING-POINT PARAMETER AND SCRATCH VECTOR.
+C              IF A COVARIANCE ESTIMATE IS REQUESTED, IT IS FOR
+C              (ALF,C) -- NONLINEAR PARAMETERS ORDERED FIRST,
+C              FOLLOWED BY LINEAR PARAMETERS.
+C      Y (IN)  RIGHT-HAND SIDE VECTOR.
+C
+C
+C  ***  EXTERNAL SUBROUTINES  ***
+C
+      DOUBLE PRECISION DD7TPR, DL7SVX, DL7SVN, DR7MDC
+      EXTERNAL DC7VFN,DIVSET, DD7TPR,DITSUM, DL7ITV,DL7SRT, DL7SVX,
+     1         DL7SVN, DN2CVP, DN2LRD, DN2RDP,  DRN2G, DQ7APL,DQ7RAD,
+     2        DQ7RFH, DR7MDC, DS7CPR,DV2AXY,DV7CPY,DV7PRM, DV7SCL,
+     3         DV7SCP
+C
+C DC7VFN... FINISHES COVARIANCE COMPUTATION.
+C DIVSET.... SUPPLIES DEFAULT PARAMETER VALUES.
+C DD7TPR... RETURNS INNER PRODUCT OF TWO VECTORS.
+C DITSUM.... PRINTS ITERATION SUMMARY, INITIAL AND FINAL ALF.
+C DL7ITV... APPLIES INVERSE-TRANSPOSE OF COMPACT LOWER TRIANG. MATRIX.
+C DL7SRT.... COMPUTES (PARTIAL) CHOLESKY FACTORIZATION.
+C DL7SVX... ESTIMATES LARGEST SING. VALUE OF LOWER TRIANG. MATRIX.
+C DL7SVN... ESTIMATES SMALLEST SING. VALUE OF LOWER TRIANG. MATRIX.
+C DN2CVP... PRINTS COVARIANCE MATRIX.
+C DN2LRD... COMPUTES COVARIANCE AND REGRESSION DIAGNOSTICS.
+C DN2RDP... PRINTS REGRESSION DIAGNOSTICS.
+C  DRN2G... UNDERLYING NONLINEAR LEAST-SQUARES SOLVER.
+C DQ7APL... APPLIES HOUSEHOLDER TRANSFORMS STORED BY DQ7RFH.
+C DQ7RFH.... COMPUTES QR FACT. VIA HOUSEHOLDER TRANSFORMS WITH PIVOTING.
+C DQ7RAD.... QR FACT., NO PIVOTING.
+C DR7MDC... RETURNS MACHINE-DEP. CONSTANTS.
+C DS7CPR... PRINTS LINEAR PARAMETERS AT SOLUTION.
+C DV2AXY.... ADDS MULTIPLE OF ONE VECTOR TO ANOTHER.
+C DV7CPY.... COPIES ONE VECTOR TO ANOTHER.
+C DV7PRM.... PERMUTES A VECTOR.
+C DV7SCL... SCALES AND COPIES ONE VECTOR TO ANOTHER.
+C DV7SCP... SETS ALL COMPONENTS OF A VECTOR TO A SCALAR.
+C
+C  ***  LOCAL VARIABLES  ***
+C
+      LOGICAL NOCOV
+      INTEGER AR1, CSAVE1, D1, DR1, DR1L, DRI, DRI1, FDH0, HSAVE, I, I1,
+     1        IPIV1, IER, IV1, J1, JLEN, K, LH, LI, LL1O2, MD, N1, N2,
+     2        NML, NRAN, PP, PP1, R1, R1L, RD1, TEMP1
+      DOUBLE PRECISION SINGTL, T
+      DOUBLE PRECISION MACHEP, NEGONE, SNGFAC, ZERO
+C
+C  ***  SUBSCRIPTS FOR IV AND V  ***
+C
+      INTEGER AR, CNVCOD, COVMAT, COVREQ, CSAVE, CVRQSV, D, FDH, H,
+     1        IERS, IPIVS, IV1SAV, IVNEED, J, LMAT, MODE, NEXTIV, NEXTV,
+     2        NFCALL, NFCOV, NFGCAL, NGCALL, NGCOV, PERM, R, RCOND,
+     3        RDREQ, RDRQSV, REGD, REGD0, RESTOR, TOOBIG, VNEED
+C
+C  ***  IV SUBSCRIPT VALUES  ***
+C
+      PARAMETER (AR=110, CNVCOD=55, COVMAT=26, COVREQ=15, CSAVE=105,
+     1           CVRQSV=106, D=27, FDH=74, H=56, IERS=108, IPIVS=109,
+     2           IV1SAV=104, IVNEED=3, J=70, LMAT=42, MODE=35,
+     3           NEXTIV=46, NEXTV=47, NFCALL=6, NFCOV=52, NFGCAL=7,
+     4           NGCALL=30, NGCOV=53, PERM=58, R=61, RCOND=53, RDREQ=57,
+     5           RDRQSV=107, REGD=67, REGD0=82, RESTOR=9, TOOBIG=2,
+     6           VNEED=4)
+      DATA MACHEP/-1.D+0/, NEGONE/-1.D+0/, SNGFAC/1.D+2/, ZERO/0.D+0/
+C
+C++++++++++++++++++++++++++++++++  BODY  ++++++++++++++++++++++++++++++
+C
+C
+      IF (IV(1) .EQ. 0) CALL DIVSET(1, IV, LIV, LV, V)
+      N1 = 1
+      NML = N
+      IV1 = IV(1)
+      IF (IV1 .LE. 2) GO TO 20
+C
+C  ***  CHECK INPUT INTEGERS  ***
+C
+      IF (P .LE. 0) GO TO 370
+      IF (L .LT. 0) GO TO 370
+      IF (N .LE. L) GO TO 370
+      IF (LA .LT. N) GO TO 370
+      IF (IV1 .LT. 12) GO TO 20
+      IF (IV1 .EQ. 14) GO TO 20
+      IF (IV1 .EQ. 12) IV(1) = 13
+C
+C  ***  FRESH START -- COMPUTE STORAGE REQUIREMENTS  ***
+C
+      IF (IV(1) .GT. 16) GO TO 370
+      LL1O2 = L*(L+1)/2
+      JLEN = N*P
+      I = L + P
+      IF (IV(RDREQ) .GT. 0 .AND. IV(COVREQ) .NE. 0) JLEN = I*(N + I + 1)
+      IF (IV(1) .NE. 13) GO TO 10
+         IV(IVNEED) = IV(IVNEED) + L
+         IV(VNEED) = IV(VNEED) + P + 2*N + JLEN + LL1O2 + L
+ 10   IF (IV(PERM) .LE. AR) IV(PERM) = AR + 1
+      CALL  DRN2G(V, V, IV, LIV, LV, N, N, N1, NML, P, V, V, V, ALF)
+      IF (IV(1) .NE. 14) GO TO 999
+C
+C  ***  STORAGE ALLOCATION  ***
+C
+      IV(IPIVS) = IV(NEXTIV)
+      IV(NEXTIV) = IV(NEXTIV) + L
+      IV(D) = IV(NEXTV)
+      IV(REGD0) = IV(D) + P
+      IV(AR) = IV(REGD0) + N
+      IV(CSAVE) = IV(AR) + LL1O2
+      IV(J) = IV(CSAVE) + L
+      IV(R) = IV(J) + JLEN
+      IV(NEXTV) = IV(R) + N
+      IV(IERS) = 0
+      IF (IV1 .EQ. 13) GO TO 999
+C
+C  ***  SET POINTERS INTO IV AND V  ***
+C
+ 20   AR1 = IV(AR)
+      D1 = IV(D)
+      DR1 = IV(J)
+      DR1L = DR1 + L
+      R1 = IV(R)
+      R1L = R1 + L
+      RD1 = IV(REGD0)
+      CSAVE1 = IV(CSAVE)
+      NML = N - L
+      IF (IV1 .LE. 2) GO TO 50
+C
+C  ***  IF F.D. HESSIAN WILL BE NEEDED (FOR COVARIANCE OR REG.
+C  ***  DIAGNOSTICS), HAVE  DRN2G COMPUTE ONLY THE PART CORRESP.
+C  ***  TO ALF WITH C FIXED...
+C
+      IF (L .LE. 0) GO TO 30
+      IV(CVRQSV) = IV(COVREQ)
+      IF (IABS(IV(COVREQ)) .GE. 3) IV(COVREQ) = 0
+      IV(RDRQSV) = IV(RDREQ)
+      IF (IV(RDREQ) .GT. 0) IV(RDREQ) = -1
+C
+ 30   N2 = NML
+      CALL  DRN2G(V(D1), V(DR1L), IV, LIV, LV, NML, N, N1, N2, P,
+     1            V(R1L), V(RD1), V, ALF)
+      IF (IABS(IV(RESTOR)-2) .EQ. 1 .AND. L .GT. 0)
+     1        CALL DV7CPY(L, C, V(CSAVE1))
+      IV1 = IV(1)
+      IF (IV1 .EQ. 2) GO TO 150
+      IF (IV1 .GT. 2) GO TO 230
+C
+C  ***  NEW FUNCTION VALUE (RESIDUAL) NEEDED  ***
+C
+      IV(IV1SAV) = IV(1)
+      IV(1) = IABS(IV1)
+      IF (IV(RESTOR) .EQ. 2 .AND. L .GT. 0) CALL DV7CPY(L, V(CSAVE1), C)
+      GO TO 999
+C
+C  ***  COMPUTE NEW RESIDUAL OR GRADIENT  ***
+C
+ 50   IV(1) = IV(IV1SAV)
+      MD = IV(MODE)
+      IF (MD .LE. 0) GO TO 60
+         NML = N
+         DR1L = DR1
+         R1L = R1
+ 60   IF (IV(TOOBIG) .NE. 0) GO TO 30
+      IF (IABS(IV1) .EQ. 2) GO TO 170
+C
+C  ***  COMPUTE NEW RESIDUAL  ***
+C
+      IF (L1 .LE. L) CALL DV7CPY(N, V(R1), Y)
+      IF (L1 .GT. L) CALL DV2AXY(N, V(R1), NEGONE, A(1,L1), Y)
+      IF (MD .GT. 0) GO TO 120
+      IER = 0
+      IF (L .LE. 0) GO TO 110
+      LL1O2 = L * (L + 1) / 2
+      IPIV1 = IV(IPIVS)
+      CALL DQ7RFH(IER, IV(IPIV1), N, LA, 0, L, A, V(AR1), LL1O2, C)
+C
+C *** DETERMINE NUMERICAL RANK OF A ***
+C
+      IF (MACHEP .LE. ZERO) MACHEP = DR7MDC(3)
+      SINGTL = SNGFAC * DBLE(MAX0(L,N)) * MACHEP
+      K = L
+      IF (IER .NE. 0) K = IER - 1
+ 70   IF (K .LE. 0) GO TO 90
+         T = DL7SVX(K, V(AR1), C, C)
+         IF (T .GT. ZERO) T = DL7SVN(K, V(AR1), C, C) / T
+         IF (T .GT. SINGTL) GO TO 80
+         K = K - 1
+         GO TO 70
+C
+C *** RECORD RANK IN IV(IERS)... IV(IERS) = 0 MEANS FULL RANK,
+C *** IV(IERS) .GT. 0 MEANS RANK IV(IERS) - 1.
+C
+ 80   IF (K .GE. L) GO TO 100
+ 90      IER = K + 1
+         CALL DV7SCP(L-K, C(K+1), ZERO)
+ 100  IV(IERS) = IER
+      IF (K .LE. 0) GO TO 110
+C
+C *** APPLY HOUSEHOLDER TRANSFORMATONS TO RESIDUALS...
+C
+      CALL DQ7APL(LA, N, K, A, V(R1), IER)
+C
+C *** COMPUTING C NOW MAY SAVE A FUNCTION EVALUATION AT
+C *** THE LAST ITERATION.
+C
+      CALL DL7ITV(K, C, V(AR1), V(R1))
+      CALL DV7PRM(L, IV(IPIV1), C)
+C
+ 110  IF(IV(1) .LT. 2) GO TO 220
+      GO TO 999
+C
+C
+C  ***  RESIDUAL COMPUTATION FOR F.D. HESSIAN  ***
+C
+ 120  IF (L .LE. 0) GO TO 140
+      DO 130 I = 1, L
+ 130     CALL DV2AXY(N, V(R1), -C(I), A(1,I), V(R1))
+ 140  IF (IV(1) .GT. 0) GO TO 30
+         IV(1) = 2
+         GO TO 160
+C
+C  ***  NEW GRADIENT (JACOBIAN) NEEDED  ***
+C
+ 150  IV(IV1SAV) = IV1
+      IF (IV(NFGCAL) .NE. IV(NFCALL)) IV(1) = 1
+ 160  CALL DV7SCP(N*P, V(DR1), ZERO)
+      GO TO 999
+C
+C  ***  COMPUTE NEW JACOBIAN  ***
+C
+ 170  NOCOV = MD .LE. P .OR. IABS(IV(COVREQ)) .GE. 3
+      FDH0 = DR1 + N*(P+L)
+      IF (NDA .LE. 0) GO TO 370
+      DO 180 I = 1, NDA
+         I1 = IN(1,I) - 1
+         IF (I1 .LT. 0) GO TO 180
+         J1 = IN(2,I)
+         K = DR1 + I1*N
+         T = NEGONE
+         IF (J1 .LE. L) T = -C(J1)
+         CALL DV2AXY(N, V(K), T, DA(1,I), V(K))
+         IF (NOCOV) GO TO 180
+         IF (J1 .GT. L) GO TO 180
+C        ***  ADD IN (L,P) PORTION OF SECOND-ORDER PART OF HESSIAN
+C        ***  FOR COVARIANCE OR REG. DIAG. COMPUTATIONS...
+         J1 = J1 + P
+         K = FDH0 + J1*(J1-1)/2 + I1
+         V(K) = V(K) - DD7TPR(N, V(R1), DA(1,I))
+ 180     CONTINUE
+      IF (IV1 .EQ. 2) GO TO 190
+         IV(1) = IV1
+         GO TO 999
+ 190  IF (L .LE. 0) GO TO 30
+      IF (MD .GT. P) GO TO 240
+      IF (MD .GT. 0) GO TO 30
+      K = DR1
+      IER = IV(IERS)
+      NRAN = L
+      IF (IER .GT. 0) NRAN = IER - 1
+      IF (NRAN .LE. 0) GO TO 210
+      DO 200 I = 1, P
+         CALL DQ7APL(LA, N, NRAN, A, V(K), IER)
+         K = K + N
+ 200     CONTINUE
+ 210  CALL DV7CPY(L, V(CSAVE1), C)
+ 220  IF (IER .EQ. 0) GO TO 30
+C
+C     *** ADJUST SUBSCRIPTS DESCRIBING R AND DR...
+C
+         NRAN = IER - 1
+         DR1L = DR1 + NRAN
+         NML = N - NRAN
+         R1L = R1 + NRAN
+         GO TO 30
+C
+C  ***  CONVERGENCE OR LIMIT REACHED  ***
+C
+ 230  IF (L .LE. 0) GO TO 350
+      IV(COVREQ) = IV(CVRQSV)
+      IV(RDREQ) = IV(RDRQSV)
+      IF (IV(1) .GT. 6) GO TO 360
+      IF (MOD(IV(RDREQ),4) .EQ. 0) GO TO 360
+      IF (IV(FDH) .LE. 0 .AND. IABS(IV(COVREQ)) .LT. 3) GO TO 360
+      IF (IV(REGD) .GT. 0) GO TO 360
+      IF (IV(COVMAT) .GT. 0) GO TO 360
+C
+C  *** PREPARE TO FINISH COMPUTING COVARIANCE MATRIX AND REG. DIAG. ***
+C
+      PP = L + P
+      I = 0
+      IF (MOD(IV(RDREQ),4) .GE. 2) I = 1
+      IF (MOD(IV(RDREQ),2) .EQ. 1 .AND. IABS(IV(COVREQ)) .EQ. 1) I = I+2
+      IV(MODE) = PP + I
+      I = DR1 + N*PP
+      K = P * (P + 1) / 2
+      I1 = IV(LMAT)
+      CALL DV7CPY(K, V(I), V(I1))
+      I = I + K
+      CALL DV7SCP(PP*(PP+1)/2 - K, V(I), ZERO)
+      IV(NFCOV) = IV(NFCOV) + 1
+      IV(NFCALL) = IV(NFCALL) + 1
+      IV(NFGCAL) = IV(NFCALL)
+      IV(CNVCOD) = IV(1)
+      IV(IV1SAV) = -1
+      IV(1) = 1
+      IV(NGCALL) = IV(NGCALL) + 1
+      IV(NGCOV) = IV(NGCOV) + 1
+      GO TO 999
+C
+C  ***  FINISH COVARIANCE COMPUTATION  ***
+C
+ 240  I = DR1 + N*P
+      DO 250 I1 = 1, L
+         CALL DV7SCL(N, V(I), NEGONE, A(1,I1))
+         I = I + N
+ 250     CONTINUE
+      PP = L + P
+      HSAVE = IV(H)
+      K = DR1 + N*PP
+      LH = PP * (PP + 1) / 2
+      IF (IABS(IV(COVREQ)) .LT. 3) GO TO 270
+      I = IV(MODE) - 4
+      IF (I .GE. PP) GO TO 260
+      CALL DV7SCP(LH, V(K), ZERO)
+      CALL DQ7RAD(N, N, PP, V, .FALSE., V(K), V(DR1), V)
+      IV(MODE) = I + 8
+      IV(1) = 2
+      IV(NGCALL) = IV(NGCALL) + 1
+      IV(NGCOV) = IV(NGCOV) + 1
+      GO TO 160
+C
+ 260  IV(MODE) = I
+      GO TO 300
+C
+ 270  PP1 = P + 1
+      DRI = DR1 + N*P
+      LI = K + P*PP1/2
+      DO 290 I = PP1, PP
+         DRI1 = DR1
+         DO 280 I1 = 1, I
+            V(LI) = V(LI) + DD7TPR(N, V(DRI), V(DRI1))
+            LI = LI + 1
+            DRI1 = DRI1 + N
+ 280        CONTINUE
+         DRI = DRI + N
+ 290     CONTINUE
+      CALL DL7SRT(PP1, PP, V(K), V(K), I)
+      IF (I .NE. 0) GO TO 310
+ 300  TEMP1 = K + LH
+      T = DL7SVN(PP, V(K), V(TEMP1), V(TEMP1))
+      IF (T .LE. ZERO) GO TO 310
+      T = T / DL7SVX(PP, V(K), V(TEMP1), V(TEMP1))
+      V(RCOND) = T
+      IF (T .GT. DR7MDC(4)) GO TO 320
+ 310     IV(REGD) = -1
+         IV(COVMAT) = -1
+         IV(FDH) = -1
+         GO TO 340
+ 320  IV(H) = TEMP1
+      IV(FDH) = IABS(HSAVE)
+      IF (IV(MODE) - PP .LT. 2) GO TO 330
+         I = IV(H)
+         CALL DV7SCP(LH, V(I), ZERO)
+ 330  CALL DN2LRD(V(DR1), IV, V(K), LH, LIV, LV, N, N, PP, V(R1),
+     1            V(RD1), V)
+ 340  CALL DC7VFN(IV, V(K), LH, LIV, LV, N, PP, V)
+      IV(H) = HSAVE
+C
+ 350  IF (IV(REGD) .EQ. 1) IV(REGD) = RD1
+ 360  IF (IV(1) .LE. 11) CALL DS7CPR(C, IV, L, LIV)
+      IF (IV(1) .GT. 6) GO TO 999
+         CALL DN2CVP(IV, LIV, LV, P+L, V)
+         CALL DN2RDP(IV, LIV, LV, N, V(RD1), V)
+         GO TO 999
+C
+ 370  IV(1) = 66
+      CALL DITSUM(V, V, IV, LIV, LV, P, V, ALF)
+C
+ 999  RETURN
+C
+C  ***  LAST CARD OF  DRNSG FOLLOWS  ***
+      END
+      SUBROUTINE DL7TVM(N, X, L, Y)
+C
+C  ***  COMPUTE  X = (L**T)*Y, WHERE  L  IS AN  N X N  LOWER
+C  ***  TRIANGULAR MATRIX STORED COMPACTLY BY ROWS.  X AND Y MAY
+C  ***  OCCUPY THE SAME STORAGE.  ***
+C
+      INTEGER N
+      DOUBLE PRECISION X(N), L(*), Y(N)
+C     DIMENSION L(N*(N+1)/2)
+      INTEGER I, IJ, I0, J
+      DOUBLE PRECISION YI, ZERO
+      PARAMETER (ZERO=0.D+0)
+C
+      I0 = 0
+      DO 20 I = 1, N
+         YI = Y(I)
+         X(I) = ZERO
+         DO 10 J = 1, I
+              IJ = I0 + J
+              X(J) = X(J) + YI*L(IJ)
+ 10           CONTINUE
+         I0 = I0 + I
+ 20      CONTINUE
+      RETURN
+C  ***  LAST CARD OF DL7TVM FOLLOWS  ***
+      END
+      SUBROUTINE DL7ITV(N, X, L, Y)
+C
+C  ***  SOLVE  (L**T)*X = Y,  WHERE  L  IS AN  N X N  LOWER TRIANGULAR
+C  ***  MATRIX STORED COMPACTLY BY ROWS.  X AND Y MAY OCCUPY THE SAME
+C  ***  STORAGE.  ***
+C
+      INTEGER N
+      DOUBLE PRECISION X(N), L(*), Y(N)
+      INTEGER I, II, IJ, IM1, I0, J, NP1
+      DOUBLE PRECISION XI, ZERO
+      PARAMETER (ZERO=0.D+0)
+C
+      DO 10 I = 1, N
+ 10      X(I) = Y(I)
+      NP1 = N + 1
+      I0 = N*(N+1)/2
+      DO 30 II = 1, N
+         I = NP1 - II
+         XI = X(I)/L(I0)
+         X(I) = XI
+         IF (I .LE. 1) GO TO 999
+         I0 = I0 - I
+         IF (XI .EQ. ZERO) GO TO 30
+         IM1 = I - 1
+         DO 20 J = 1, IM1
+              IJ = I0 + J
+              X(J) = X(J) - XI*L(IJ)
+ 20           CONTINUE
+ 30      CONTINUE
+ 999  RETURN
+C  ***  LAST CARD OF DL7ITV FOLLOWS  ***
+      END
+      SUBROUTINE DRMNGB(B, D, FX, G, IV, LIV, LV, N, V, X)
+C
+C  ***  CARRY OUT  DMNGB (SIMPLY BOUNDED MINIMIZATION) ITERATIONS,
+C  ***  USING DOUBLE-DOGLEG/BFGS STEPS.
+C
+C  ***  PARAMETER DECLARATIONS  ***
+C
+      INTEGER LIV, LV, N
+      INTEGER IV(LIV)
+      DOUBLE PRECISION B(2,N), D(N), FX, G(N), V(LV), X(N)
+C
+C--------------------------  PARAMETER USAGE  --------------------------
+C
+C B.... VECTOR OF LOWER AND UPPER BOUNDS ON X.
+C D.... SCALE VECTOR.
+C FX... FUNCTION VALUE.
+C G.... GRADIENT VECTOR.
+C IV... INTEGER VALUE ARRAY.
+C LIV.. LENGTH OF IV (AT LEAST 59) + N.
+C LV... LENGTH OF V (AT LEAST 71 + N*(N+19)/2).
+C N.... NUMBER OF VARIABLES (COMPONENTS IN X AND G).
+C V.... FLOATING-POINT VALUE ARRAY.
+C X.... VECTOR OF PARAMETERS TO BE OPTIMIZED.
+C
+C  ***  DISCUSSION  ***
+C
+C        PARAMETERS IV, N, V, AND X ARE THE SAME AS THE CORRESPONDING
+C     ONES TO  DMNGB (WHICH SEE), EXCEPT THAT V CAN BE SHORTER (SINCE
+C     THE PART OF V THAT  DMNGB USES FOR STORING G IS NOT NEEDED).
+C     MOREOVER, COMPARED WITH  DMNGB, IV(1) MAY HAVE THE TWO ADDITIONAL
+C     OUTPUT VALUES 1 AND 2, WHICH ARE EXPLAINED BELOW, AS IS THE USE
+C     OF IV(TOOBIG) AND IV(NFGCAL).  THE VALUE IV(G), WHICH IS AN
+C     OUTPUT VALUE FROM  DMNGB (AND SMSNOB), IS NOT REFERENCED BY
+C     DRMNGB OR THE SUBROUTINES IT CALLS.
+C        FX AND G NEED NOT HAVE BEEN INITIALIZED WHEN DRMNGB IS CALLED
+C     WITH IV(1) = 12, 13, OR 14.
+C
+C IV(1) = 1 MEANS THE CALLER SHOULD SET FX TO F(X), THE FUNCTION VALUE
+C             AT X, AND CALL DRMNGB AGAIN, HAVING CHANGED NONE OF THE
+C             OTHER PARAMETERS.  AN EXCEPTION OCCURS IF F(X) CANNOT BE
+C             (E.G. IF OVERFLOW WOULD OCCUR), WHICH MAY HAPPEN BECAUSE
+C             OF AN OVERSIZED STEP.  IN THIS CASE THE CALLER SHOULD SET
+C             IV(TOOBIG) = IV(2) TO 1, WHICH WILL CAUSE DRMNGB TO IG-
+C             NORE FX AND TRY A SMALLER STEP.  THE PARAMETER NF THAT
+C              DMNGB PASSES TO CALCF (FOR POSSIBLE USE BY CALCG) IS A
+C             COPY OF IV(NFCALL) = IV(6).
+C IV(1) = 2 MEANS THE CALLER SHOULD SET G TO G(X), THE GRADIENT VECTOR
+C             OF F AT X, AND CALL DRMNGB AGAIN, HAVING CHANGED NONE OF
+C             THE OTHER PARAMETERS EXCEPT POSSIBLY THE SCALE VECTOR D
+C             WHEN IV(DTYPE) = 0.  THE PARAMETER NF THAT  DMNGB PASSES
+C             TO CALCG IS IV(NFGCAL) = IV(7).  IF G(X) CANNOT BE
+C             EVALUATED, THEN THE CALLER MAY SET IV(NFGCAL) TO 0, IN
+C             WHICH CASE DRMNGB WILL RETURN WITH IV(1) = 65.
+C.
+C  ***  GENERAL  ***
+C
+C     CODED BY DAVID M. GAY (DECEMBER 1979).  REVISED SEPT. 1982.
+C     THIS SUBROUTINE WAS WRITTEN IN CONNECTION WITH RESEARCH SUPPORTED
+C     IN PART BY THE NATIONAL SCIENCE FOUNDATION UNDER GRANTS
+C     MCS-7600324 AND MCS-7906671.
+C
+C        (SEE  DMNG FOR REFERENCES.)
+C
+C+++++++++++++++++++++++++++  DECLARATIONS  ++++++++++++++++++++++++++++
+C
+C  ***  LOCAL VARIABLES  ***
+C
+      INTEGER DG1, DSTEP1, DUMMY, G01, I, I1, IPI, IPN, J, K, L, LSTGST,
+     1        N1, NP1, NWTST1, RSTRST, STEP1, TEMP0, TEMP1, TD1, TG1,
+     2        W1, X01, Z
+      DOUBLE PRECISION GI, T, XI
+C
+C     ***  CONSTANTS  ***
+C
+      DOUBLE PRECISION NEGONE, ONE, ONEP2, ZERO
+C
+C  ***  NO INTRINSIC FUNCTIONS  ***
+C
+C  ***  EXTERNAL FUNCTIONS AND SUBROUTINES  ***
+C
+      LOGICAL STOPX
+      DOUBLE PRECISION DD7TPR, DRLDST, DV2NRM
+      EXTERNAL DA7SST, DD7DGB,DIVSET, DD7TPR, I7SHFT,DITSUM, DL7TVM,
+     1         DL7UPD,DL7VML,DPARCK, DQ7RSH, DRLDST, STOPX, DV2NRM,
+     2        DV2AXY,DV7CPY, DV7IPR, DV7SCP, DV7VMP, DW7ZBF
+C
+C DA7SST.... ASSESSES CANDIDATE STEP.
+C DD7DGB... COMPUTES SIMPLY BOUNDED DOUBLE-DOGLEG (CANDIDATE) STEP.
+C DIVSET.... SUPPLIES DEFAULT IV AND V INPUT COMPONENTS.
+C DD7TPR... RETURNS INNER PRODUCT OF TWO VECTORS.
+C I7SHFT... CYCLICALLLY SHIFTS AN ARRAY OF INTEGERS.
+C DITSUM.... PRINTS ITERATION SUMMARY AND INFO ON INITIAL AND FINAL X.
+C DL7TVM... MULTIPLIES TRANSPOSE OF LOWER TRIANGLE TIMES VECTOR.
+C LUPDT.... UPDATES CHOLESKY FACTOR OF HESSIAN APPROXIMATION.
+C DL7VML.... MULTIPLIES LOWER TRIANGLE TIMES VECTOR.
+C DPARCK.... CHECKS VALIDITY OF INPUT IV AND V VALUES.
+C DQ7RSH... CYCLICALLY SHIFTS CHOLESKY FACTOR.
+C DRLDST... COMPUTES V(RELDX) = RELATIVE STEP SIZE.
+C STOPX.... RETURNS .TRUE. IF THE BREAK KEY HAS BEEN PRESSED.
+C DV2NRM... RETURNS THE 2-NORM OF A VECTOR.
+C DV2AXY.... COMPUTES SCALAR TIMES ONE VECTOR PLUS ANOTHER.
+C DV7CPY.... COPIES ONE VECTOR TO ANOTHER.
+C DV7IPR... CYCLICALLY SHIFTS A FLOATING-POINT ARRAY.
+C DV7SCP... SETS ALL ELEMENTS OF A VECTOR TO A SCALAR.
+C DV7VMP... MULTIPLIES VECTOR BY VECTOR RAISED TO POWER (COMPONENTWISE).
+C DW7ZBF... COMPUTES W AND Z FOR DL7UPD CORRESPONDING TO BFGS UPDATE.
+C
+C  ***  SUBSCRIPTS FOR IV AND V  ***
+C
+      INTEGER CNVCOD, DG, DGNORM, DINIT, DSTNRM, F, F0, FDIF,
+     1        GTSTEP, INCFAC, INITH, IRC, IVNEED, KAGQT, LMAT,
+     2        LMAX0, LMAXS, MODE, MODEL, MXFCAL, MXITER, NC, NEXTIV,
+     3        NEXTV, NFCALL, NFGCAL, NGCALL, NITER, NWTSTP, PERM,
+     4        PREDUC, RADFAC, RADINC, RADIUS, RAD0, RELDX, RESTOR, STEP,
+     4        STGLIM, STLSTG, TOOBIG, TUNER4, TUNER5, VNEED, XIRC, X0
+C
+C  ***  IV SUBSCRIPT VALUES  ***
+C
+C  ***  (NOTE THAT NC IS STORED IN IV(G0)) ***
+C
+      PARAMETER (CNVCOD=55, DG=37, INITH=25, IRC=29, IVNEED=3, KAGQT=33,
+     1           MODE=35, MODEL=5, MXFCAL=17, MXITER=18, NC=48,
+     2           NEXTIV=46, NEXTV=47, NFCALL=6, NFGCAL=7, NGCALL=30,
+     3           NITER=31, NWTSTP=34, PERM=58, RADINC=8, RESTOR=9,
+     4           STEP=40, STGLIM=11, STLSTG=41, TOOBIG=2, XIRC=13,
+     5           X0=43)
+C
+C  ***  V SUBSCRIPT VALUES  ***
+C
+      PARAMETER (DGNORM=1, DINIT=38, DSTNRM=2, F=10, F0=13, FDIF=11,
+     1           GTSTEP=4, INCFAC=23, LMAT=42, LMAX0=35, LMAXS=36,
+     2           PREDUC=7, RADFAC=16, RADIUS=8, RAD0=9, RELDX=17,
+     3           TUNER4=29, TUNER5=30, VNEED=4)
+C
+      PARAMETER (NEGONE=-1.D+0, ONE=1.D+0, ONEP2=1.2D+0, ZERO=0.D+0)
+C
+C+++++++++++++++++++++++++++++++  BODY  ++++++++++++++++++++++++++++++++
+C
+      I = IV(1)
+      IF (I .EQ. 1) GO TO 70
+      IF (I .EQ. 2) GO TO 80
+C
+C  ***  CHECK VALIDITY OF IV AND V INPUT VALUES  ***
+C
+      IF (IV(1) .EQ. 0) CALL DIVSET(2, IV, LIV, LV, V)
+      IF (IV(1) .LT. 12) GO TO 10
+      IF (IV(1) .GT. 13) GO TO 10
+         IV(VNEED) = IV(VNEED) + N*(N+19)/2
+         IV(IVNEED) = IV(IVNEED) + N
+ 10   CALL DPARCK(2, D, IV, LIV, LV, N, V)
+      I = IV(1) - 2
+      IF (I .GT. 12) GO TO 999
+      GO TO (250, 250, 250, 250, 250, 250, 190, 150, 190, 20, 20, 30), I
+C
+C  ***  STORAGE ALLOCATION  ***
+C
+ 20   L = IV(LMAT)
+      IV(X0) = L + N*(N+1)/2
+      IV(STEP) = IV(X0) + 2*N
+      IV(STLSTG) = IV(STEP) + 2*N
+      IV(NWTSTP) = IV(STLSTG) + N
+      IV(DG) = IV(NWTSTP) + 2*N
+      IV(NEXTV) = IV(DG) + 2*N
+      IV(NEXTIV) = IV(PERM) + N
+      IF (IV(1) .NE. 13) GO TO 30
+         IV(1) = 14
+         GO TO 999
+C
+C  ***  INITIALIZATION  ***
+C
+ 30   IV(NITER) = 0
+      IV(NFCALL) = 1
+      IV(NGCALL) = 1
+      IV(NFGCAL) = 1
+      IV(MODE) = -1
+      IV(MODEL) = 1
+      IV(STGLIM) = 1
+      IV(TOOBIG) = 0
+      IV(CNVCOD) = 0
+      IV(RADINC) = 0
+      IV(NC) = N
+      V(RAD0) = ZERO
+C
+C  ***  CHECK CONSISTENCY OF B AND INITIALIZE IP ARRAY  ***
+C
+      IPI = IV(PERM)
+      DO 40 I = 1, N
+         IV(IPI) = I
+         IPI = IPI + 1
+         IF (B(1,I) .GT. B(2,I)) GO TO 410
+ 40      CONTINUE
+C
+      IF (V(DINIT) .GE. ZERO) CALL DV7SCP(N, D, V(DINIT))
+      IF (IV(INITH) .NE. 1) GO TO 60
+C
+C     ***  SET THE INITIAL HESSIAN APPROXIMATION TO DIAG(D)**-2  ***
+C
+         L = IV(LMAT)
+         CALL DV7SCP(N*(N+1)/2, V(L), ZERO)
+         K = L - 1
+         DO 50 I = 1, N
+              K = K + I
+              T = D(I)
+              IF (T .LE. ZERO) T = ONE
+              V(K) = T
+ 50           CONTINUE
+C
+C  ***  GET INITIAL FUNCTION VALUE  ***
+C
+ 60   IV(1) = 1
+      GO TO 440
+C
+ 70   V(F) = FX
+      IF (IV(MODE) .GE. 0) GO TO 250
+      V(F0) = FX
+      IV(1) = 2
+      IF (IV(TOOBIG) .EQ. 0) GO TO 999
+         IV(1) = 63
+         GO TO 430
+C
+C  ***  MAKE SURE GRADIENT COULD BE COMPUTED  ***
+C
+ 80   IF (IV(TOOBIG) .EQ. 0) GO TO 90
+         IV(1) = 65
+         GO TO 430
+C
+C  ***  CHOOSE INITIAL PERMUTATION  ***
+C
+ 90   IPI = IV(PERM)
+      IPN = IPI + N
+      N1 = N
+      NP1 = N + 1
+      L = IV(LMAT)
+      W1 = IV(NWTSTP) + N
+      K = N - IV(NC)
+      DO 120 I = 1, N
+         IPN = IPN - 1
+         J = IV(IPN)
+         IF (B(1,J) .GE. B(2,J)) GO TO 100
+         XI = X(J)
+         GI = G(J)
+         IF (XI .LE. B(1,J) .AND. GI .GT. ZERO) GO TO 100
+         IF (XI .GE. B(2,J) .AND. GI .LT. ZERO) GO TO 100
+C           *** DISALLOW CONVERGENCE IF X(J) HAS JUST BEEN FREED ***
+            IF (I .LE. K) IV(CNVCOD) = 0
+            GO TO 120
+ 100     I1 = NP1 - I
+         IF (I1 .GE. N1) GO TO 110
+            CALL I7SHFT(N1, I1, IV(IPI))
+            CALL DQ7RSH(I1, N1, .FALSE., G, V(L), V(W1))
+ 110        N1 = N1 - 1
+ 120     CONTINUE
+C
+      IV(NC) = N1
+      V(DGNORM) = ZERO
+      IF (N1 .LE. 0) GO TO 130
+         DG1 = IV(DG)
+         CALL DV7VMP(N, V(DG1), G, D, -1)
+         CALL DV7IPR(N, IV(IPI), V(DG1))
+         V(DGNORM) = DV2NRM(N1, V(DG1))
+ 130  IF (IV(CNVCOD) .NE. 0) GO TO 420
+      IF (IV(MODE) .EQ. 0) GO TO 370
+C
+C  ***  ALLOW FIRST STEP TO HAVE SCALED 2-NORM AT MOST V(LMAX0)  ***
+C
+      V(RADIUS) = V(LMAX0)
+C
+      IV(MODE) = 0
+C
+C
+C-----------------------------  MAIN LOOP  -----------------------------
+C
+C
+C  ***  PRINT ITERATION SUMMARY, CHECK ITERATION LIMIT  ***
+C
+ 140  CALL DITSUM(D, G, IV, LIV, LV, N, V, X)
+ 150  K = IV(NITER)
+      IF (K .LT. IV(MXITER)) GO TO 160
+         IV(1) = 10
+         GO TO 430
+C
+C  ***  UPDATE RADIUS  ***
+C
+ 160  IV(NITER) = K + 1
+      IF (K .EQ. 0) GO TO 170
+      T = V(RADFAC) * V(DSTNRM)
+      IF (V(RADFAC) .LT. ONE .OR. T .GT. V(RADIUS)) V(RADIUS) = T
+C
+C  ***  INITIALIZE FOR START OF NEXT ITERATION  ***
+C
+ 170  X01 = IV(X0)
+      V(F0) = V(F)
+      IV(IRC) = 4
+      IV(KAGQT) = -1
+C
+C     ***  COPY X TO X0  ***
+C
+      CALL DV7CPY(N, V(X01), X)
+C
+C  ***  CHECK STOPX AND FUNCTION EVALUATION LIMIT  ***
+C
+ 180  IF (.NOT. STOPX(DUMMY)) GO TO 200
+         IV(1) = 11
+         GO TO 210
+C
+C     ***  COME HERE WHEN RESTARTING AFTER FUNC. EVAL. LIMIT OR STOPX.
+C
+ 190  IF (V(F) .GE. V(F0)) GO TO 200
+         V(RADFAC) = ONE
+         K = IV(NITER)
+         GO TO 160
+C
+ 200  IF (IV(NFCALL) .LT. IV(MXFCAL)) GO TO 220
+         IV(1) = 9
+ 210     IF (V(F) .GE. V(F0)) GO TO 430
+C
+C        ***  IN CASE OF STOPX OR FUNCTION EVALUATION LIMIT WITH
+C        ***  IMPROVED V(F), EVALUATE THE GRADIENT AT X.
+C
+              IV(CNVCOD) = IV(1)
+              GO TO 360
+C
+C. . . . . . . . . . . . .  COMPUTE CANDIDATE STEP  . . . . . . . . . .
+C
+ 220  STEP1 = IV(STEP)
+      DG1 = IV(DG)
+      NWTST1 = IV(NWTSTP)
+      W1 = NWTST1 + N
+      DSTEP1 = STEP1 + N
+      IPI = IV(PERM)
+      L = IV(LMAT)
+      TG1 = DG1 + N
+      X01 = IV(X0)
+      TD1 = X01 + N
+      CALL DD7DGB(B, D, V(DG1), V(DSTEP1), G, IV(IPI), IV(KAGQT),
+     1            V(L), LV, N, IV(NC), V(NWTST1), V(STEP1), V(TD1),
+     2            V(TG1), V, V(W1), V(X01))
+      IF (IV(IRC) .NE. 6) GO TO 230
+         IF (IV(RESTOR) .NE. 2) GO TO 250
+         RSTRST = 2
+         GO TO 260
+C
+C  ***  CHECK WHETHER EVALUATING F(X0 + STEP) LOOKS WORTHWHILE  ***
+C
+ 230  IV(TOOBIG) = 0
+      IF (V(DSTNRM) .LE. ZERO) GO TO 250
+      IF (IV(IRC) .NE. 5) GO TO 240
+      IF (V(RADFAC) .LE. ONE) GO TO 240
+      IF (V(PREDUC) .GT. ONEP2 * V(FDIF)) GO TO 240
+         IF (IV(RESTOR) .NE. 2) GO TO 250
+         RSTRST = 0
+         GO TO 260
+C
+C  ***  COMPUTE F(X0 + STEP)  ***
+C
+ 240  CALL DV2AXY(N, X, ONE, V(STEP1), V(X01))
+      IV(NFCALL) = IV(NFCALL) + 1
+      IV(1) = 1
+      GO TO 440
+C
+C. . . . . . . . . . . . .  ASSESS CANDIDATE STEP  . . . . . . . . . . .
+C
+ 250  RSTRST = 3
+ 260  X01 = IV(X0)
+      V(RELDX) = DRLDST(N, D, X, V(X01))
+      CALL DA7SST(IV, LIV, LV, V)
+      STEP1 = IV(STEP)
+      LSTGST = IV(STLSTG)
+      I = IV(RESTOR) + 1
+      GO TO (300, 270, 280, 290), I
+ 270  CALL DV7CPY(N, X, V(X01))
+      GO TO 300
+ 280   CALL DV7CPY(N, V(LSTGST), X)
+       GO TO 300
+ 290     CALL DV7CPY(N, X, V(LSTGST))
+         CALL DV2AXY(N, V(STEP1), NEGONE, V(X01), X)
+         V(RELDX) = DRLDST(N, D, X, V(X01))
+         IV(RESTOR) = RSTRST
+C
+ 300  K = IV(IRC)
+      GO TO (310,340,340,340,310,320,330,330,330,330,330,330,400,370), K
+C
+C     ***  RECOMPUTE STEP WITH CHANGED RADIUS  ***
+C
+ 310     V(RADIUS) = V(RADFAC) * V(DSTNRM)
+         GO TO 180
+C
+C  ***  COMPUTE STEP OF LENGTH V(LMAXS) FOR SINGULAR CONVERGENCE TEST.
+C
+ 320  V(RADIUS) = V(LMAXS)
+      GO TO 220
+C
+C  ***  CONVERGENCE OR FALSE CONVERGENCE  ***
+C
+ 330  IV(CNVCOD) = K - 4
+      IF (V(F) .GE. V(F0)) GO TO 420
+         IF (IV(XIRC) .EQ. 14) GO TO 420
+              IV(XIRC) = 14
+C
+C. . . . . . . . . . . .  PROCESS ACCEPTABLE STEP  . . . . . . . . . . .
+C
+ 340  X01 = IV(X0)
+      STEP1 = IV(STEP)
+      CALL DV2AXY(N, V(STEP1), NEGONE, V(X01), X)
+      IF (IV(IRC) .NE. 3) GO TO 360
+C
+C     ***  SET  TEMP1 = HESSIAN * STEP  FOR USE IN GRADIENT TESTS  ***
+C
+C     ***  USE X0 AS TEMPORARY...
+C
+         IPI = IV(PERM)
+         CALL DV7CPY(N, V(X01), V(STEP1))
+         CALL DV7IPR(N, IV(IPI), V(X01))
+         L = IV(LMAT)
+         CALL DL7TVM(N, V(X01), V(L), V(X01))
+         CALL DL7VML(N, V(X01), V(L), V(X01))
+C
+C        *** UNPERMUTE X0 INTO TEMP1 ***
+C
+         TEMP1 = IV(STLSTG)
+         TEMP0 = TEMP1 - 1
+         DO 350 I = 1, N
+            J = IV(IPI)
+            IPI = IPI + 1
+            K = TEMP0 + J
+            V(K) = V(X01)
+            X01 = X01 + 1
+ 350        CONTINUE
+C
+C  ***  SAVE OLD GRADIENT, COMPUTE NEW ONE  ***
+C
+ 360  G01 = IV(NWTSTP) + N
+      CALL DV7CPY(N, V(G01), G)
+      IV(NGCALL) = IV(NGCALL) + 1
+      IV(TOOBIG) = 0
+      IV(1) = 2
+      GO TO 999
+C
+C  ***  INITIALIZATIONS -- G0 = G - G0, ETC.  ***
+C
+ 370  G01 = IV(NWTSTP) + N
+      CALL DV2AXY(N, V(G01), NEGONE, V(G01), G)
+      STEP1 = IV(STEP)
+      TEMP1 = IV(STLSTG)
+      IF (IV(IRC) .NE. 3) GO TO 390
+C
+C  ***  SET V(RADFAC) BY GRADIENT TESTS  ***
+C
+C     ***  SET  TEMP1 = DIAG(D)**-1 * (HESSIAN*STEP + (G(X0)-G(X)))  ***
+C
+         CALL DV2AXY(N, V(TEMP1), NEGONE, V(G01), V(TEMP1))
+         CALL DV7VMP(N, V(TEMP1), V(TEMP1), D, -1)
+C
+C        ***  DO GRADIENT TESTS  ***
+C
+         IF (DV2NRM(N, V(TEMP1)) .LE. V(DGNORM) * V(TUNER4))
+     1                  GO TO 380
+              IF (DD7TPR(N, G, V(STEP1))
+     1                  .GE. V(GTSTEP) * V(TUNER5))  GO TO 390
+ 380               V(RADFAC) = V(INCFAC)
+C
+C  ***  UPDATE H, LOOP  ***
+C
+ 390  W1 = IV(NWTSTP)
+      Z = IV(X0)
+      L = IV(LMAT)
+      IPI = IV(PERM)
+      CALL DV7IPR(N, IV(IPI), V(STEP1))
+      CALL DV7IPR(N, IV(IPI), V(G01))
+      CALL DW7ZBF(V(L), N, V(STEP1), V(W1), V(G01), V(Z))
+C
+C     ** USE THE N-VECTORS STARTING AT V(STEP1) AND V(G01) FOR SCRATCH..
+      CALL DL7UPD(V(TEMP1), V(STEP1), V(L), V(G01), V(L), N, V(W1),
+     1            V(Z))
+      IV(1) = 2
+      GO TO 140
+C
+C. . . . . . . . . . . . . .  MISC. DETAILS  . . . . . . . . . . . . . .
+C
+C  ***  BAD PARAMETERS TO ASSESS  ***
+C
+ 400  IV(1) = 64
+      GO TO 430
+C
+C  ***  INCONSISTENT B  ***
+C
+ 410  IV(1) = 82
+      GO TO 430
+C
+C  ***  PRINT SUMMARY OF FINAL ITERATION AND OTHER REQUESTED ITEMS  ***
+C
+ 420  IV(1) = IV(CNVCOD)
+      IV(CNVCOD) = 0
+ 430  CALL DITSUM(D, G, IV, LIV, LV, N, V, X)
+      GO TO 999
+C
+C  ***  PROJECT X INTO FEASIBLE REGION (PRIOR TO COMPUTING F OR G)  ***
+C
+ 440  DO 450 I = 1, N
+         IF (X(I) .LT. B(1,I)) X(I) = B(1,I)
+         IF (X(I) .GT. B(2,I)) X(I) = B(2,I)
+ 450     CONTINUE
+C
+ 999  RETURN
+C
+C  ***  LAST CARD OF DRMNGB FOLLOWS  ***
+      END
+      SUBROUTINE DS7GRD (ALPHA, D, ETA0, FX, G, IRC, N, W, X)
+C
+C  ***  COMPUTE FINITE DIFFERENCE GRADIENT BY STWEART*S SCHEME  ***
+C
+C     ***  PARAMETERS  ***
+C
+      INTEGER IRC, N
+      DOUBLE PRECISION ALPHA(N), D(N), ETA0, FX, G(N), W(6), X(N)
+C
+C.......................................................................
+C
+C     ***  PURPOSE  ***
+C
+C        THIS SUBROUTINE USES AN EMBELLISHED FORM OF THE FINITE-DIFFER-
+C     ENCE SCHEME PROPOSED BY STEWART (REF. 1) TO APPROXIMATE THE
+C     GRADIENT OF THE FUNCTION F(X), WHOSE VALUES ARE SUPPLIED BY
+C     REVERSE COMMUNICATION.
+C
+C     ***  PARAMETER DESCRIPTION  ***
+C
+C  ALPHA IN  (APPROXIMATE) DIAGONAL ELEMENTS OF THE HESSIAN OF F(X).
+C      D IN  SCALE VECTOR SUCH THAT D(I)*X(I), I = 1,...,N, ARE IN
+C             COMPARABLE UNITS.
+C   ETA0 IN  ESTIMATED BOUND ON RELATIVE ERROR IN THE FUNCTION VALUE...
+C             (TRUE VALUE) = (COMPUTED VALUE)*(1+E),   WHERE
+C             ABS(E) .LE. ETA0.
+C     FX I/O ON INPUT,  FX  MUST BE THE COMPUTED VALUE OF F(X).  ON
+C             OUTPUT WITH IRC = 0, FX HAS BEEN RESTORED TO ITS ORIGINAL
+C             VALUE, THE ONE IT HAD WHEN DS7GRD WAS LAST CALLED WITH
+C             IRC = 0.
+C      G I/O ON INPUT WITH IRC = 0, G SHOULD CONTAIN AN APPROXIMATION
+C             TO THE GRADIENT OF F NEAR X, E.G., THE GRADIENT AT THE
+C             PREVIOUS ITERATE.  WHEN DS7GRD RETURNS WITH IRC = 0, G IS
+C             THE DESIRED FINITE-DIFFERENCE APPROXIMATION TO THE
+C             GRADIENT AT X.
+C    IRC I/O INPUT/RETURN CODE... BEFORE THE VERY FIRST CALL ON DS7GRD,
+C             THE CALLER MUST SET IRC TO 0.  WHENEVER DS7GRD RETURNS A
+C             NONZERO VALUE FOR IRC, IT HAS PERTURBED SOME COMPONENT OF
+C             X... THE CALLER SHOULD EVALUATE F(X) AND CALL DS7GRD
+C             AGAIN WITH FX = F(X).
+C      N IN  THE NUMBER OF VARIABLES (COMPONENTS OF X) ON WHICH F
+C             DEPENDS.
+C      X I/O ON INPUT WITH IRC = 0, X IS THE POINT AT WHICH THE
+C             GRADIENT OF F IS DESIRED.  ON OUTPUT WITH IRC NONZERO, X
+C             IS THE POINT AT WHICH F SHOULD BE EVALUATED.  ON OUTPUT
+C             WITH IRC = 0, X HAS BEEN RESTORED TO ITS ORIGINAL VALUE
+C             (THE ONE IT HAD WHEN DS7GRD WAS LAST CALLED WITH IRC = 0)
+C             AND G CONTAINS THE DESIRED GRADIENT APPROXIMATION.
+C      W I/O WORK VECTOR OF LENGTH 6 IN WHICH DS7GRD SAVES CERTAIN
+C             QUANTITIES WHILE THE CALLER IS EVALUATING F(X) AT A
+C             PERTURBED X.
+C
+C     ***  APPLICATION AND USAGE RESTRICTIONS  ***
+C
+C        THIS ROUTINE IS INTENDED FOR USE WITH QUASI-NEWTON ROUTINES
+C     FOR UNCONSTRAINED MINIMIZATION (IN WHICH CASE  ALPHA  COMES FROM
+C     THE DIAGONAL OF THE QUASI-NEWTON HESSIAN APPROXIMATION).
+C
+C     ***  ALGORITHM NOTES  ***
+C
+C        THIS CODE DEPARTS FROM THE SCHEME PROPOSED BY STEWART (REF. 1)
+C     IN ITS GUARDING AGAINST OVERLY LARGE OR SMALL STEP SIZES AND ITS
+C     HANDLING OF SPECIAL CASES (SUCH AS ZERO COMPONENTS OF ALPHA OR G).
+C
+C     ***  REFERENCES  ***
+C
+C 1. STEWART, G.W. (1967), A MODIFICATION OF DAVIDON*S MINIMIZATION
+C        METHOD TO ACCEPT DIFFERENCE APPROXIMATIONS OF DERIVATIVES,
+C        J. ASSOC. COMPUT. MACH. 14, PP. 72-83.
+C
+C     ***  HISTORY  ***
+C
+C     DESIGNED AND CODED BY DAVID M. GAY (SUMMER 1977/SUMMER 1980).
+C
+C     ***  GENERAL  ***
+C
+C        THIS ROUTINE WAS PREPARED IN CONNECTION WITH WORK SUPPORTED BY
+C     THE NATIONAL SCIENCE FOUNDATION UNDER GRANTS MCS76-00324 AND
+C     MCS-7906671.
+C
+C.......................................................................
+C
+C     *****  EXTERNAL FUNCTION  *****
+C
+      DOUBLE PRECISION DR7MDC
+      EXTERNAL DR7MDC
+C DR7MDC... RETURNS MACHINE-DEPENDENT CONSTANTS.
+C
+C     ***** INTRINSIC FUNCTIONS *****
+C/+
+      DOUBLE PRECISION DSQRT
+C/
+C     ***** LOCAL VARIABLES *****
+C
+      INTEGER FH, FX0, HSAVE, I, XISAVE
+      DOUBLE PRECISION AAI, AFX, AFXETA, AGI, ALPHAI, AXI, AXIBAR,
+     1                 DISCON, ETA, GI, H, HMIN
+      DOUBLE PRECISION C2000, FOUR, HMAX0, HMIN0, H0, MACHEP, ONE, P002,
+     1                 THREE, TWO, ZERO
+C
+      PARAMETER (C2000=2.0D+3, FOUR=4.0D+0, HMAX0=0.02D+0, HMIN0=5.0D+1,
+     1     ONE=1.0D+0, P002=0.002D+0, THREE=3.0D+0,
+     2     TWO=2.0D+0, ZERO=0.0D+0)
+      PARAMETER (FH=3, FX0=4, HSAVE=5, XISAVE=6)
+C
+C---------------------------------  BODY  ------------------------------
+C
+      IF (IRC .LT. 0) GO TO 140
+      IF (IRC .GT. 0) GO TO 210
+C
+C     ***  FRESH START -- GET MACHINE-DEPENDENT CONSTANTS  ***
+C
+C     STORE MACHEP IN W(1) AND H0 IN W(2), WHERE MACHEP IS THE UNIT
+C     ROUNDOFF (THE SMALLEST POSITIVE NUMBER SUCH THAT
+C     1 + MACHEP .GT. 1  AND  1 - MACHEP .LT. 1),  AND  H0 IS THE
+C     SQUARE-ROOT OF MACHEP.
+C
+      W(1) = DR7MDC(3)
+      W(2) = DSQRT(W(1))
+C
+      W(FX0) = FX
+C
+C     ***  INCREMENT  I  AND START COMPUTING  G(I)  ***
+C
+ 110  I = IABS(IRC) + 1
+      IF (I .GT. N) GO TO 300
+         IRC = I
+         AFX = DABS(W(FX0))
+         MACHEP = W(1)
+         H0 = W(2)
+         HMIN = HMIN0 * MACHEP
+         W(XISAVE) = X(I)
+         AXI = DABS(X(I))
+         AXIBAR = DMAX1(AXI, ONE/D(I))
+         GI = G(I)
+         AGI = DABS(GI)
+         ETA = DABS(ETA0)
+         IF (AFX .GT. ZERO) ETA = DMAX1(ETA, AGI*AXI*MACHEP/AFX)
+         ALPHAI = ALPHA(I)
+         IF (ALPHAI .EQ. ZERO) GO TO 170
+         IF (GI .EQ. ZERO .OR. FX .EQ. ZERO) GO TO 180
+         AFXETA = AFX*ETA
+         AAI = DABS(ALPHAI)
+C
+C        *** COMPUTE H = STEWART*S FORWARD-DIFFERENCE STEP SIZE.
+C
+         IF (GI**2 .LE. AFXETA*AAI) GO TO 120
+              H = TWO*DSQRT(AFXETA/AAI)
+              H = H*(ONE - AAI*H/(THREE*AAI*H + FOUR*AGI))
+              GO TO 130
+C120     H = TWO*(AFXETA*AGI/(AAI**2))**(ONE/THREE)
+ 120     H = TWO * (AFXETA*AGI)**(ONE/THREE) * AAI**(-TWO/THREE)
+         H = H*(ONE - TWO*AGI/(THREE*AAI*H + FOUR*AGI))
+C
+C        ***  ENSURE THAT  H  IS NOT INSIGNIFICANTLY SMALL  ***
+C
+ 130     H = DMAX1(H, HMIN*AXIBAR)
+C
+C        *** USE FORWARD DIFFERENCE IF BOUND ON TRUNCATION ERROR IS AT
+C        *** MOST 10**-3.
+C
+         IF (AAI*H .LE. P002*AGI) GO TO 160
+C
+C        *** COMPUTE H = STEWART*S STEP FOR CENTRAL DIFFERENCE.
+C
+         DISCON = C2000*AFXETA
+         H = DISCON/(AGI + DSQRT(GI**2 + AAI*DISCON))
+C
+C        ***  ENSURE THAT  H  IS NEITHER TOO SMALL NOR TOO BIG  ***
+C
+         H = DMAX1(H, HMIN*AXIBAR)
+         IF (H .GE. HMAX0*AXIBAR) H = AXIBAR * H0**(TWO/THREE)
+C
+C        ***  COMPUTE CENTRAL DIFFERENCE  ***
+C
+         IRC = -I
+         GO TO 200
+C
+ 140     H = -W(HSAVE)
+         I = IABS(IRC)
+         IF (H .GT. ZERO) GO TO 150
+         W(FH) = FX
+         GO TO 200
+C
+ 150     G(I) = (W(FH) - FX) / (TWO * H)
+         X(I) = W(XISAVE)
+         GO TO 110
+C
+C     ***  COMPUTE FORWARD DIFFERENCES IN VARIOUS CASES  ***
+C
+ 160     IF (H .GE. HMAX0*AXIBAR) H = H0 * AXIBAR
+         IF (ALPHAI*GI .LT. ZERO) H = -H
+         GO TO 200
+ 170     H = AXIBAR
+         GO TO 200
+ 180     H = H0 * AXIBAR
+C
+ 200     X(I) = W(XISAVE) + H
+         W(HSAVE) = H
+         GO TO 999
+C
+C     ***  COMPUTE ACTUAL FORWARD DIFFERENCE  ***
+C
+ 210     G(IRC) = (FX - W(FX0)) / W(HSAVE)
+         X(IRC) = W(XISAVE)
+         GO TO 110
+C
+C  ***  RESTORE FX AND INDICATE THAT G HAS BEEN COMPUTED  ***
+C
+ 300  FX = W(FX0)
+      IRC = 0
+C
+ 999  RETURN
+C  ***  LAST CARD OF DS7GRD FOLLOWS  ***
+      END
+      SUBROUTINE DG7QTS(D, DIG, DIHDI, KA, L, P, STEP, V, W)
+C
+C  *** COMPUTE GOLDFELD-QUANDT-TROTTER STEP BY MORE-HEBDEN TECHNIQUE ***
+C  ***  (NL2SOL VERSION 2.2), MODIFIED A LA MORE AND SORENSEN  ***
+C
+C  ***  PARAMETER DECLARATIONS  ***
+C
+      INTEGER KA, P
+      DOUBLE PRECISION D(P), DIG(P), DIHDI(*), L(*), V(21), STEP(P),
+     1                 W(*)
+C     DIMENSION DIHDI(P*(P+1)/2), L(P*(P+1)/2), W(4*P+7)
+C
+C+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+C
+C  ***  PURPOSE  ***
+C
+C        GIVEN THE (COMPACTLY STORED) LOWER TRIANGLE OF A SCALED
+C     HESSIAN (APPROXIMATION) AND A NONZERO SCALED GRADIENT VECTOR,
+C     THIS SUBROUTINE COMPUTES A GOLDFELD-QUANDT-TROTTER STEP OF
+C     APPROXIMATE LENGTH V(RADIUS) BY THE MORE-HEBDEN TECHNIQUE.  IN
+C     OTHER WORDS, STEP IS COMPUTED TO (APPROXIMATELY) MINIMIZE
+C     PSI(STEP) = (G**T)*STEP + 0.5*(STEP**T)*H*STEP  SUCH THAT THE
+C     2-NORM OF D*STEP IS AT MOST (APPROXIMATELY) V(RADIUS), WHERE
+C     G  IS THE GRADIENT,  H  IS THE HESSIAN, AND  D  IS A DIAGONAL
+C     SCALE MATRIX WHOSE DIAGONAL IS STORED IN THE PARAMETER D.
+C     (DG7QTS ASSUMES  DIG = D**-1 * G  AND  DIHDI = D**-1 * H * D**-1.)
+C
+C  ***  PARAMETER DESCRIPTION  ***
+C
+C     D (IN)  = THE SCALE VECTOR, I.E. THE DIAGONAL OF THE SCALE
+C              MATRIX  D  MENTIONED ABOVE UNDER PURPOSE.
+C   DIG (IN)  = THE SCALED GRADIENT VECTOR, D**-1 * G.  IF G = 0, THEN
+C              STEP = 0  AND  V(STPPAR) = 0  ARE RETURNED.
+C DIHDI (IN)  = LOWER TRIANGLE OF THE SCALED HESSIAN (APPROXIMATION),
+C              I.E., D**-1 * H * D**-1, STORED COMPACTLY BY ROWS., I.E.,
+C              IN THE ORDER (1,1), (2,1), (2,2), (3,1), (3,2), ETC.
+C    KA (I/O) = THE NUMBER OF HEBDEN ITERATIONS (SO FAR) TAKEN TO DETER-
+C              MINE STEP.  KA .LT. 0 ON INPUT MEANS THIS IS THE FIRST
+C              ATTEMPT TO DETERMINE STEP (FOR THE PRESENT DIG AND DIHDI)
+C              -- KA IS INITIALIZED TO 0 IN THIS CASE.  OUTPUT WITH
+C              KA = 0  (OR V(STPPAR) = 0)  MEANS  STEP = -(H**-1)*G.
+C     L (I/O) = WORKSPACE OF LENGTH P*(P+1)/2 FOR CHOLESKY FACTORS.
+C     P (IN)  = NUMBER OF PARAMETERS -- THE HESSIAN IS A  P X P  MATRIX.
+C  STEP (I/O) = THE STEP COMPUTED.
+C     V (I/O) CONTAINS VARIOUS CONSTANTS AND VARIABLES DESCRIBED BELOW.
+C     W (I/O) = WORKSPACE OF LENGTH 4*P + 6.
+C
+C  ***  ENTRIES IN V  ***
+C
+C V(DGNORM) (I/O) = 2-NORM OF (D**-1)*G.
+C V(DSTNRM) (OUTPUT) = 2-NORM OF D*STEP.
+C V(DST0)   (I/O) = 2-NORM OF D*(H**-1)*G (FOR POS. DEF. H ONLY), OR
+C             OVERESTIMATE OF SMALLEST EIGENVALUE OF (D**-1)*H*(D**-1).
+C V(EPSLON) (IN)  = MAX. REL. ERROR ALLOWED FOR PSI(STEP).  FOR THE
+C             STEP RETURNED, PSI(STEP) WILL EXCEED ITS OPTIMAL VALUE
+C             BY LESS THAN -V(EPSLON)*PSI(STEP).  SUGGESTED VALUE = 0.1.
+C V(GTSTEP) (OUT) = INNER PRODUCT BETWEEN G AND STEP.
+C V(NREDUC) (OUT) = PSI(-(H**-1)*G) = PSI(NEWTON STEP)  (FOR POS. DEF.
+C             H ONLY -- V(NREDUC) IS SET TO ZERO OTHERWISE).
+C V(PHMNFC) (IN)  = TOL. (TOGETHER WITH V(PHMXFC)) FOR ACCEPTING STEP
+C             (MORE*S SIGMA).  THE ERROR V(DSTNRM) - V(RADIUS) MUST LIE
+C             BETWEEN V(PHMNFC)*V(RADIUS) AND V(PHMXFC)*V(RADIUS).
+C V(PHMXFC) (IN)  (SEE V(PHMNFC).)
+C             SUGGESTED VALUES -- V(PHMNFC) = -0.25, V(PHMXFC) = 0.5.
+C V(PREDUC) (OUT) = PSI(STEP) = PREDICTED OBJ. FUNC. REDUCTION FOR STEP.
+C V(RADIUS) (IN)  = RADIUS OF CURRENT (SCALED) TRUST REGION.
+C V(RAD0)   (I/O) = VALUE OF V(RADIUS) FROM PREVIOUS CALL.
+C V(STPPAR) (I/O) IS NORMALLY THE MARQUARDT PARAMETER, I.E. THE ALPHA
+C             DESCRIBED BELOW UNDER ALGORITHM NOTES.  IF H + ALPHA*D**2
+C             (SEE ALGORITHM NOTES) IS (NEARLY) SINGULAR, HOWEVER,
+C             THEN V(STPPAR) = -ALPHA.
+C
+C  ***  USAGE NOTES  ***
+C
+C     IF IT IS DESIRED TO RECOMPUTE STEP USING A DIFFERENT VALUE OF
+C     V(RADIUS), THEN THIS ROUTINE MAY BE RESTARTED BY CALLING IT
+C     WITH ALL PARAMETERS UNCHANGED EXCEPT V(RADIUS).  (THIS EXPLAINS
+C     WHY STEP AND W ARE LISTED AS I/O).  ON AN INITIAL CALL (ONE WITH
+C     KA .LT. 0), STEP AND W NEED NOT BE INITIALIZED AND ONLY COMPO-
+C     NENTS V(EPSLON), V(STPPAR), V(PHMNFC), V(PHMXFC), V(RADIUS), AND
+C     V(RAD0) OF V MUST BE INITIALIZED.
+C
+C  ***  ALGORITHM NOTES  ***
+C
+C        THE DESIRED G-Q-T STEP (REF. 2, 3, 4, 6) SATISFIES
+C     (H + ALPHA*D**2)*STEP = -G  FOR SOME NONNEGATIVE ALPHA SUCH THAT
+C     H + ALPHA*D**2 IS POSITIVE SEMIDEFINITE.  ALPHA AND STEP ARE
+C     COMPUTED BY A SCHEME ANALOGOUS TO THE ONE DESCRIBED IN REF. 5.
+C     ESTIMATES OF THE SMALLEST AND LARGEST EIGENVALUES OF THE HESSIAN
+C     ARE OBTAINED FROM THE GERSCHGORIN CIRCLE THEOREM ENHANCED BY A
+C     SIMPLE FORM OF THE SCALING DESCRIBED IN REF. 7.  CASES IN WHICH
+C     H + ALPHA*D**2 IS NEARLY (OR EXACTLY) SINGULAR ARE HANDLED BY
+C     THE TECHNIQUE DISCUSSED IN REF. 2.  IN THESE CASES, A STEP OF
+C     (EXACT) LENGTH V(RADIUS) IS RETURNED FOR WHICH PSI(STEP) EXCEEDS
+C     ITS OPTIMAL VALUE BY LESS THAN -V(EPSLON)*PSI(STEP).  THE TEST
+C     SUGGESTED IN REF. 6 FOR DETECTING THE SPECIAL CASE IS PERFORMED
+C     ONCE TWO MATRIX FACTORIZATIONS HAVE BEEN DONE -- DOING SO SOONER
+C     SEEMS TO DEGRADE THE PERFORMANCE OF OPTIMIZATION ROUTINES THAT
+C     CALL THIS ROUTINE.
+C
+C  ***  FUNCTIONS AND SUBROUTINES CALLED  ***
+C
+C DD7TPR - RETURNS INNER PRODUCT OF TWO VECTORS.
+C DL7ITV - APPLIES INVERSE-TRANSPOSE OF COMPACT LOWER TRIANG. MATRIX.
+C DL7IVM - APPLIES INVERSE OF COMPACT LOWER TRIANG. MATRIX.
+C DL7SRT  - FINDS CHOLESKY FACTOR (OF COMPACTLY STORED LOWER TRIANG.).
+C DL7SVN - RETURNS APPROX. TO MIN. SING. VALUE OF LOWER TRIANG. MATRIX.
+C DR7MDC - RETURNS MACHINE-DEPENDENT CONSTANTS.
+C DV2NRM - RETURNS 2-NORM OF A VECTOR.
+C
+C  ***  REFERENCES  ***
+C
+C 1.  DENNIS, J.E., GAY, D.M., AND WELSCH, R.E. (1981), AN ADAPTIVE
+C             NONLINEAR LEAST-SQUARES ALGORITHM, ACM TRANS. MATH.
+C             SOFTWARE, VOL. 7, NO. 3.
+C 2.  GAY, D.M. (1981), COMPUTING OPTIMAL LOCALLY CONSTRAINED STEPS,
+C             SIAM J. SCI. STATIST. COMPUTING, VOL. 2, NO. 2, PP.
+C             186-197.
+C 3.  GOLDFELD, S.M., QUANDT, R.E., AND TROTTER, H.F. (1966),
+C             MAXIMIZATION BY QUADRATIC HILL-CLIMBING, ECONOMETRICA 34,
+C             PP. 541-551.
+C 4.  HEBDEN, M.D. (1973), AN ALGORITHM FOR MINIMIZATION USING EXACT
+C             SECOND DERIVATIVES, REPORT T.P. 515, THEORETICAL PHYSICS
+C             DIV., A.E.R.E. HARWELL, OXON., ENGLAND.
+C 5.  MORE, J.J. (1978), THE LEVENBERG-MARQUARDT ALGORITHM, IMPLEMEN-
+C             TATION AND THEORY, PP.105-116 OF SPRINGER LECTURE NOTES
+C             IN MATHEMATICS NO. 630, EDITED BY G.A. WATSON, SPRINGER-
+C             VERLAG, BERLIN AND NEW YORK.
+C 6.  MORE, J.J., AND SORENSEN, D.C. (1981), COMPUTING A TRUST REGION
+C             STEP, TECHNICAL REPORT ANL-81-83, ARGONNE NATIONAL LAB.
+C 7.  VARGA, R.S. (1965), MINIMAL GERSCHGORIN SETS, PACIFIC J. MATH. 15,
+C             PP. 719-729.
+C
+C  ***  GENERAL  ***
+C
+C     CODED BY DAVID M. GAY.
+C     THIS SUBROUTINE WAS WRITTEN IN CONNECTION WITH RESEARCH
+C     SUPPORTED BY THE NATIONAL SCIENCE FOUNDATION UNDER GRANTS
+C     MCS-7600324, DCR75-10143, 76-14311DSS, MCS76-11989, AND
+C     MCS-7906671.
+C
+C+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+C
+C  ***  LOCAL VARIABLES  ***
+C
+      LOGICAL RESTRT
+      INTEGER DGGDMX, DIAG, DIAG0, DSTSAV, EMAX, EMIN, I, IM1, INC, IRC,
+     1        J, K, KALIM, KAMIN, K1, LK0, PHIPIN, Q, Q0, UK0, X
+      DOUBLE PRECISION ALPHAK, AKI, AKK, DELTA, DST, EPS, GTSTA, LK,
+     1                 OLDPHI, PHI, PHIMAX, PHIMIN, PSIFAC, RAD, RADSQ,
+     2                 ROOT, SI, SK, SW, T, TWOPSI, T1, T2, UK, WI
+C
+C     ***  CONSTANTS  ***
+      DOUBLE PRECISION BIG, DGXFAC, EPSFAC, FOUR, HALF, KAPPA, NEGONE,
+     1                 ONE, P001, SIX, THREE, TWO, ZERO
+C
+C  ***  INTRINSIC FUNCTIONS  ***
+C/+
+      DOUBLE PRECISION DSQRT
+C/
+C  ***  EXTERNAL FUNCTIONS AND SUBROUTINES  ***
+C
+      DOUBLE PRECISION DD7TPR, DL7SVN, DR7MDC, DV2NRM
+      EXTERNAL DD7TPR, DL7ITV, DL7IVM,DL7SRT, DL7SVN, DR7MDC, DV2NRM
+C
+C  ***  SUBSCRIPTS FOR V  ***
+C
+      INTEGER DGNORM, DSTNRM, DST0, EPSLON, GTSTEP, STPPAR, NREDUC,
+     1        PHMNFC, PHMXFC, PREDUC, RADIUS, RAD0
+      PARAMETER (DGNORM=1, DSTNRM=2, DST0=3, EPSLON=19, GTSTEP=4,
+     1           NREDUC=6, PHMNFC=20, PHMXFC=21, PREDUC=7, RADIUS=8,
+     2           RAD0=9, STPPAR=5)
+C
+      PARAMETER (EPSFAC=50.0D+0, FOUR=4.0D+0, HALF=0.5D+0,
+     1     KAPPA=2.0D+0, NEGONE=-1.0D+0, ONE=1.0D+0, P001=1.0D-3,
+     2     SIX=6.0D+0, THREE=3.0D+0, TWO=2.0D+0, ZERO=0.0D+0)
+      SAVE DGXFAC
+      DATA BIG/0.D+0/, DGXFAC/0.D+0/
+C
+C  ***  BODY  ***
+C
+      IF (BIG .LE. ZERO) BIG = DR7MDC(6)
+C
+C     ***  STORE LARGEST ABS. ENTRY IN (D**-1)*H*(D**-1) AT W(DGGDMX).
+      DGGDMX = P + 1
+C     ***  STORE GERSCHGORIN OVER- AND UNDERESTIMATES OF THE LARGEST
+C     ***  AND SMALLEST EIGENVALUES OF (D**-1)*H*(D**-1) AT W(EMAX)
+C     ***  AND W(EMIN) RESPECTIVELY.
+      EMAX = DGGDMX + 1
+      EMIN = EMAX + 1
+C     ***  FOR USE IN RECOMPUTING STEP, THE FINAL VALUES OF LK, UK, DST,
+C     ***  AND THE INVERSE DERIVATIVE OF MORE*S PHI AT 0 (FOR POS. DEF.
+C     ***  H) ARE STORED IN W(LK0), W(UK0), W(DSTSAV), AND W(PHIPIN)
+C     ***  RESPECTIVELY.
+      LK0 = EMIN + 1
+      PHIPIN = LK0 + 1
+      UK0 = PHIPIN + 1
+      DSTSAV = UK0 + 1
+C     ***  STORE DIAG OF (D**-1)*H*(D**-1) IN W(DIAG),...,W(DIAG0+P).
+      DIAG0 = DSTSAV
+      DIAG = DIAG0 + 1
+C     ***  STORE -D*STEP IN W(Q),...,W(Q0+P).
+      Q0 = DIAG0 + P
+      Q = Q0 + 1
+C     ***  ALLOCATE STORAGE FOR SCRATCH VECTOR X  ***
+      X = Q + P
+      RAD = V(RADIUS)
+      RADSQ = RAD**2
+C     ***  PHITOL = MAX. ERROR ALLOWED IN DST = V(DSTNRM) = 2-NORM OF
+C     ***  D*STEP.
+      PHIMAX = V(PHMXFC) * RAD
+      PHIMIN = V(PHMNFC) * RAD
+      PSIFAC = BIG
+      T1 = TWO * V(EPSLON) / (THREE * (FOUR * (V(PHMNFC) + ONE) *
+     1                       (KAPPA + ONE)  +  KAPPA  +  TWO) * RAD)
+      IF (T1 .LT. BIG*DMIN1(RAD,ONE)) PSIFAC = T1 / RAD
+C     ***  OLDPHI IS USED TO DETECT LIMITS OF NUMERICAL ACCURACY.  IF
+C     ***  WE RECOMPUTE STEP AND IT DOES NOT CHANGE, THEN WE ACCEPT IT.
+      OLDPHI = ZERO
+      EPS = V(EPSLON)
+      IRC = 0
+      RESTRT = .FALSE.
+      KALIM = KA + 50
+C
+C  ***  START OR RESTART, DEPENDING ON KA  ***
+C
+      IF (KA .GE. 0) GO TO 290
+C
+C  ***  FRESH START  ***
+C
+      K = 0
+      UK = NEGONE
+      KA = 0
+      KALIM = 50
+      V(DGNORM) = DV2NRM(P, DIG)
+      V(NREDUC) = ZERO
+      V(DST0) = ZERO
+      KAMIN = 3
+      IF (V(DGNORM) .EQ. ZERO) KAMIN = 0
+C
+C     ***  STORE DIAG(DIHDI) IN W(DIAG0+1),...,W(DIAG0+P)  ***
+C
+      J = 0
+      DO 10 I = 1, P
+         J = J + I
+         K1 = DIAG0 + I
+         W(K1) = DIHDI(J)
+ 10      CONTINUE
+C
+C     ***  DETERMINE W(DGGDMX), THE LARGEST ELEMENT OF DIHDI  ***
+C
+      T1 = ZERO
+      J = P * (P + 1) / 2
+      DO 20 I = 1, J
+         T = DABS(DIHDI(I))
+         IF (T1 .LT. T) T1 = T
+ 20      CONTINUE
+      W(DGGDMX) = T1
+C
+C  ***  TRY ALPHA = 0  ***
+C
+ 30   CALL DL7SRT(1, P, L, DIHDI, IRC)
+      IF (IRC .EQ. 0) GO TO 50
+C        ***  INDEF. H -- UNDERESTIMATE SMALLEST EIGENVALUE, USE THIS
+C        ***  ESTIMATE TO INITIALIZE LOWER BOUND LK ON ALPHA.
+         J = IRC*(IRC+1)/2
+         T = L(J)
+         L(J) = ONE
+         DO 40 I = 1, IRC
+ 40           W(I) = ZERO
+         W(IRC) = ONE
+         CALL DL7ITV(IRC, W, L, W)
+         T1 = DV2NRM(IRC, W)
+         LK = -T / T1 / T1
+         V(DST0) = -LK
+         IF (RESTRT) GO TO 210
+         GO TO 70
+C
+C     ***  POSITIVE DEFINITE H -- COMPUTE UNMODIFIED NEWTON STEP.  ***
+ 50   LK = ZERO
+      T = DL7SVN(P, L, W(Q), W(Q))
+      IF (T .GE. ONE) GO TO 60
+         IF (V(DGNORM) .GE. T*T*BIG) GO TO 70
+ 60   CALL DL7IVM(P, W(Q), L, DIG)
+      GTSTA = DD7TPR(P, W(Q), W(Q))
+      V(NREDUC) = HALF * GTSTA
+      CALL DL7ITV(P, W(Q), L, W(Q))
+      DST = DV2NRM(P, W(Q))
+      V(DST0) = DST
+      PHI = DST - RAD
+      IF (PHI .LE. PHIMAX) GO TO 260
+      IF (RESTRT) GO TO 210
+C
+C  ***  PREPARE TO COMPUTE GERSCHGORIN ESTIMATES OF LARGEST (AND
+C  ***  SMALLEST) EIGENVALUES.  ***
+C
+ 70   K = 0
+      DO 100 I = 1, P
+         WI = ZERO
+         IF (I .EQ. 1) GO TO 90
+         IM1 = I - 1
+         DO 80 J = 1, IM1
+              K = K + 1
+              T = DABS(DIHDI(K))
+              WI = WI + T
+              W(J) = W(J) + T
+ 80           CONTINUE
+ 90      W(I) = WI
+         K = K + 1
+ 100     CONTINUE
+C
+C  ***  (UNDER-)ESTIMATE SMALLEST EIGENVALUE OF (D**-1)*H*(D**-1)  ***
+C
+      K = 1
+      T1 = W(DIAG) - W(1)
+      IF (P .LE. 1) GO TO 120
+      DO 110 I = 2, P
+         J = DIAG0 + I
+         T = W(J) - W(I)
+         IF (T .GE. T1) GO TO 110
+              T1 = T
+              K = I
+ 110     CONTINUE
+C
+ 120  SK = W(K)
+      J = DIAG0 + K
+      AKK = W(J)
+      K1 = K*(K-1)/2 + 1
+      INC = 1
+      T = ZERO
+      DO 150 I = 1, P
+         IF (I .EQ. K) GO TO 130
+         AKI = DABS(DIHDI(K1))
+         SI = W(I)
+         J = DIAG0 + I
+         T1 = HALF * (AKK - W(J) + SI - AKI)
+         T1 = T1 + DSQRT(T1*T1 + SK*AKI)
+         IF (T .LT. T1) T = T1
+         IF (I .LT. K) GO TO 140
+ 130     INC = I
+ 140     K1 = K1 + INC
+ 150     CONTINUE
+C
+      W(EMIN) = AKK - T
+      UK = V(DGNORM)/RAD - W(EMIN)
+      IF (V(DGNORM) .EQ. ZERO) UK = UK + P001 + P001*UK
+      IF (UK .LE. ZERO) UK = P001
+C
+C  ***  COMPUTE GERSCHGORIN (OVER-)ESTIMATE OF LARGEST EIGENVALUE  ***
+C
+      K = 1
+      T1 = W(DIAG) + W(1)
+      IF (P .LE. 1) GO TO 170
+      DO 160 I = 2, P
+         J = DIAG0 + I
+         T = W(J) + W(I)
+         IF (T .LE. T1) GO TO 160
+              T1 = T
+              K = I
+ 160     CONTINUE
+C
+ 170  SK = W(K)
+      J = DIAG0 + K
+      AKK = W(J)
+      K1 = K*(K-1)/2 + 1
+      INC = 1
+      T = ZERO
+      DO 200 I = 1, P
+         IF (I .EQ. K) GO TO 180
+         AKI = DABS(DIHDI(K1))
+         SI = W(I)
+         J = DIAG0 + I
+         T1 = HALF * (W(J) + SI - AKI - AKK)
+         T1 = T1 + DSQRT(T1*T1 + SK*AKI)
+         IF (T .LT. T1) T = T1
+         IF (I .LT. K) GO TO 190
+ 180     INC = I
+ 190     K1 = K1 + INC
+ 200     CONTINUE
+C
+      W(EMAX) = AKK + T
+      LK = DMAX1(LK, V(DGNORM)/RAD - W(EMAX))
+C
+C     ***  ALPHAK = CURRENT VALUE OF ALPHA (SEE ALG. NOTES ABOVE).  WE
+C     ***  USE MORE*S SCHEME FOR INITIALIZING IT.
+      ALPHAK = DABS(V(STPPAR)) * V(RAD0)/RAD
+      ALPHAK = DMIN1(UK, DMAX1(ALPHAK, LK))
+C
+      IF (IRC .NE. 0) GO TO 210
+C
+C  ***  COMPUTE L0 FOR POSITIVE DEFINITE H  ***
+C
+      CALL DL7IVM(P, W, L, W(Q))
+      T = DV2NRM(P, W)
+      W(PHIPIN) = RAD / T / T
+      LK = DMAX1(LK, PHI*W(PHIPIN))
+C
+C  ***  SAFEGUARD ALPHAK AND ADD ALPHAK*I TO (D**-1)*H*(D**-1)  ***
+C
+ 210  KA = KA + 1
+      IF (-V(DST0) .GE. ALPHAK .OR. ALPHAK .LT. LK .OR. ALPHAK .GE. UK)
+     1                      ALPHAK = UK * DMAX1(P001, DSQRT(LK/UK))
+      IF (ALPHAK .LE. ZERO) ALPHAK = HALF * UK
+      IF (ALPHAK .LE. ZERO) ALPHAK = UK
+      K = 0
+      DO 220 I = 1, P
+         K = K + I
+         J = DIAG0 + I
+         DIHDI(K) = W(J) + ALPHAK
+ 220     CONTINUE
+C
+C  ***  TRY COMPUTING CHOLESKY DECOMPOSITION  ***
+C
+      CALL DL7SRT(1, P, L, DIHDI, IRC)
+      IF (IRC .EQ. 0) GO TO 240
+C
+C  ***  (D**-1)*H*(D**-1) + ALPHAK*I  IS INDEFINITE -- OVERESTIMATE
+C  ***  SMALLEST EIGENVALUE FOR USE IN UPDATING LK  ***
+C
+      J = (IRC*(IRC+1))/2
+      T = L(J)
+      L(J) = ONE
+      DO 230 I = 1, IRC
+ 230     W(I) = ZERO
+      W(IRC) = ONE
+      CALL DL7ITV(IRC, W, L, W)
+      T1 = DV2NRM(IRC, W)
+      LK = ALPHAK - T/T1/T1
+      V(DST0) = -LK
+      IF (UK .LT. LK) UK = LK
+      IF (ALPHAK .LT. LK) GO TO 210
+C
+C  ***  NASTY CASE -- EXACT GERSCHGORIN BOUNDS.  FUDGE LK, UK...
+C
+      T = P001 * ALPHAK
+      IF (T .LE. ZERO) T = P001
+      LK = ALPHAK + T
+      IF (UK .LE. LK) UK = LK + T
+      GO TO 210
+C
+C  ***  ALPHAK MAKES (D**-1)*H*(D**-1) POSITIVE DEFINITE.
+C  ***  COMPUTE Q = -D*STEP, CHECK FOR CONVERGENCE.  ***
+C
+ 240  CALL DL7IVM(P, W(Q), L, DIG)
+      GTSTA = DD7TPR(P, W(Q), W(Q))
+      CALL DL7ITV(P, W(Q), L, W(Q))
+      DST = DV2NRM(P, W(Q))
+      PHI = DST - RAD
+      IF (PHI .LE. PHIMAX .AND. PHI .GE. PHIMIN) GO TO 270
+      IF (PHI .EQ. OLDPHI) GO TO 270
+      OLDPHI = PHI
+      IF (PHI .LT. ZERO) GO TO 330
+C
+C  ***  UNACCEPTABLE ALPHAK -- UPDATE LK, UK, ALPHAK  ***
+C
+ 250  IF (KA .GE. KALIM) GO TO 270
+C     ***  THE FOLLOWING DMIN1 IS NECESSARY BECAUSE OF RESTARTS  ***
+      IF (PHI .LT. ZERO) UK = DMIN1(UK, ALPHAK)
+C     *** KAMIN = 0 ONLY IFF THE GRADIENT VANISHES  ***
+      IF (KAMIN .EQ. 0) GO TO 210
+      CALL DL7IVM(P, W, L, W(Q))
+C     *** THE FOLLOWING, COMMENTED CALCULATION OF ALPHAK IS SOMETIMES
+C     *** SAFER BUT WORSE IN PERFORMANCE...
+C     T1 = DST / DV2NRM(P, W)
+C     ALPHAK = ALPHAK  +  T1 * (PHI/RAD) * T1
+      T1 = DV2NRM(P, W)
+      ALPHAK = ALPHAK  +  (PHI/T1) * (DST/T1) * (DST/RAD)
+      LK = DMAX1(LK, ALPHAK)
+      ALPHAK = LK
+      GO TO 210
+C
+C  ***  ACCEPTABLE STEP ON FIRST TRY  ***
+C
+ 260  ALPHAK = ZERO
+C
+C  ***  SUCCESSFUL STEP IN GENERAL.  COMPUTE STEP = -(D**-1)*Q  ***
+C
+ 270  DO 280 I = 1, P
+         J = Q0 + I
+         STEP(I) = -W(J)/D(I)
+ 280     CONTINUE
+      V(GTSTEP) = -GTSTA
+      V(PREDUC) = HALF * (DABS(ALPHAK)*DST*DST + GTSTA)
+      GO TO 410
+C
+C
+C  ***  RESTART WITH NEW RADIUS  ***
+C
+ 290  IF (V(DST0) .LE. ZERO .OR. V(DST0) - RAD .GT. PHIMAX) GO TO 310
+C
+C     ***  PREPARE TO RETURN NEWTON STEP  ***
+C
+         RESTRT = .TRUE.
+         KA = KA + 1
+         K = 0
+         DO 300 I = 1, P
+              K = K + I
+              J = DIAG0 + I
+              DIHDI(K) = W(J)
+ 300          CONTINUE
+         UK = NEGONE
+         GO TO 30
+C
+ 310  KAMIN = KA + 3
+      IF (V(DGNORM) .EQ. ZERO) KAMIN = 0
+      IF (KA .EQ. 0) GO TO 50
+C
+      DST = W(DSTSAV)
+      ALPHAK = DABS(V(STPPAR))
+      PHI = DST - RAD
+      T = V(DGNORM)/RAD
+      UK = T - W(EMIN)
+      IF (V(DGNORM) .EQ. ZERO) UK = UK + P001 + P001*UK
+      IF (UK .LE. ZERO) UK = P001
+      IF (RAD .GT. V(RAD0)) GO TO 320
+C
+C        ***  SMALLER RADIUS  ***
+         LK = ZERO
+         IF (ALPHAK .GT. ZERO) LK = W(LK0)
+         LK = DMAX1(LK, T - W(EMAX))
+         IF (V(DST0) .GT. ZERO) LK = DMAX1(LK, (V(DST0)-RAD)*W(PHIPIN))
+         GO TO 250
+C
+C     ***  BIGGER RADIUS  ***
+ 320  IF (ALPHAK .GT. ZERO) UK = DMIN1(UK, W(UK0))
+      LK = DMAX1(ZERO, -V(DST0), T - W(EMAX))
+      IF (V(DST0) .GT. ZERO) LK = DMAX1(LK, (V(DST0)-RAD)*W(PHIPIN))
+      GO TO 250
+C
+C  ***  DECIDE WHETHER TO CHECK FOR SPECIAL CASE... IN PRACTICE (FROM
+C  ***  THE STANDPOINT OF THE CALLING OPTIMIZATION CODE) IT SEEMS BEST
+C  ***  NOT TO CHECK UNTIL A FEW ITERATIONS HAVE FAILED -- HENCE THE
+C  ***  TEST ON KAMIN BELOW.
+C
+ 330  DELTA = ALPHAK + DMIN1(ZERO, V(DST0))
+      TWOPSI = ALPHAK*DST*DST + GTSTA
+      IF (KA .GE. KAMIN) GO TO 340
+C     *** IF THE TEST IN REF. 2 IS SATISFIED, FALL THROUGH TO HANDLE
+C     *** THE SPECIAL CASE (AS SOON AS THE MORE-SORENSEN TEST DETECTS
+C     *** IT).
+      IF (PSIFAC .GE. BIG) GO TO 340
+      IF (DELTA .GE. PSIFAC*TWOPSI) GO TO 370
+C
+C  ***  CHECK FOR THE SPECIAL CASE OF  H + ALPHA*D**2  (NEARLY)
+C  ***  SINGULAR.  USE ONE STEP OF INVERSE POWER METHOD WITH START
+C  ***  FROM DL7SVN TO OBTAIN APPROXIMATE EIGENVECTOR CORRESPONDING
+C  ***  TO SMALLEST EIGENVALUE OF (D**-1)*H*(D**-1).  DL7SVN RETURNS
+C  ***  X AND W WITH  L*W = X.
+C
+ 340  T = DL7SVN(P, L, W(X), W)
+C
+C     ***  NORMALIZE W  ***
+      DO 350 I = 1, P
+ 350     W(I) = T*W(I)
+C     ***  COMPLETE CURRENT INV. POWER ITER. -- REPLACE W BY (L**-T)*W.
+      CALL DL7ITV(P, W, L, W)
+      T2 = ONE/DV2NRM(P, W)
+      DO 360 I = 1, P
+ 360     W(I) = T2*W(I)
+      T = T2 * T
+C
+C  ***  NOW W IS THE DESIRED APPROXIMATE (UNIT) EIGENVECTOR AND
+C  ***  T*X = ((D**-1)*H*(D**-1) + ALPHAK*I)*W.
+C
+      SW = DD7TPR(P, W(Q), W)
+      T1 = (RAD + DST) * (RAD - DST)
+      ROOT = DSQRT(SW*SW + T1)
+      IF (SW .LT. ZERO) ROOT = -ROOT
+      SI = T1 / (SW + ROOT)
+C
+C  ***  THE ACTUAL TEST FOR THE SPECIAL CASE...
+C
+      IF ((T2*SI)**2 .LE. EPS*(DST**2 + ALPHAK*RADSQ)) GO TO 380
+C
+C  ***  UPDATE UPPER BOUND ON SMALLEST EIGENVALUE (WHEN NOT POSITIVE)
+C  ***  (AS RECOMMENDED BY MORE AND SORENSEN) AND CONTINUE...
+C
+      IF (V(DST0) .LE. ZERO) V(DST0) = DMIN1(V(DST0), T2**2 - ALPHAK)
+      LK = DMAX1(LK, -V(DST0))
+C
+C  ***  CHECK WHETHER WE CAN HOPE TO DETECT THE SPECIAL CASE IN
+C  ***  THE AVAILABLE ARITHMETIC.  ACCEPT STEP AS IT IS IF NOT.
+C
+C     ***  IF NOT YET AVAILABLE, OBTAIN MACHINE DEPENDENT VALUE DGXFAC.
+ 370  IF (DGXFAC .EQ. ZERO) DGXFAC = EPSFAC * DR7MDC(3)
+C
+      IF (DELTA .GT. DGXFAC*W(DGGDMX)) GO TO 250
+         GO TO 270
+C
+C  ***  SPECIAL CASE DETECTED... NEGATE ALPHAK TO INDICATE SPECIAL CASE
+C
+ 380  ALPHAK = -ALPHAK
+      V(PREDUC) = HALF * TWOPSI
+C
+C  ***  ACCEPT CURRENT STEP IF ADDING SI*W WOULD LEAD TO A
+C  ***  FURTHER RELATIVE REDUCTION IN PSI OF LESS THAN V(EPSLON)/3.
+C
+      T1 = ZERO
+      T = SI*(ALPHAK*SW - HALF*SI*(ALPHAK + T*DD7TPR(P,W(X),W)))
+      IF (T .LT. EPS*TWOPSI/SIX) GO TO 390
+         V(PREDUC) = V(PREDUC) + T
+         DST = RAD
+         T1 = -SI
+ 390  DO 400 I = 1, P
+         J = Q0 + I
+         W(J) = T1*W(I) - W(J)
+         STEP(I) = W(J) / D(I)
+ 400     CONTINUE
+      V(GTSTEP) = DD7TPR(P, DIG, W(Q))
+C
+C  ***  SAVE VALUES FOR USE IN A POSSIBLE RESTART  ***
+C
+ 410  V(DSTNRM) = DST
+      V(STPPAR) = ALPHAK
+      W(LK0) = LK
+      W(UK0) = UK
+      V(RAD0) = RAD
+      W(DSTSAV) = DST
+C
+C     ***  RESTORE DIAGONAL OF DIHDI  ***
+C
+      J = 0
+      DO 420 I = 1, P
+         J = J + I
+         K = DIAG0 + I
+         DIHDI(J) = W(K)
+ 420     CONTINUE
+C
+      RETURN
+C
+C  ***  LAST CARD OF DG7QTS FOLLOWS  ***
+      END
+      SUBROUTINE DW7ZBF (L, N, S, W, Y, Z)
+C
+C  ***  COMPUTE  Y  AND  Z  FOR  DL7UPD  CORRESPONDING TO BFGS UPDATE.
+C
+      INTEGER N
+      DOUBLE PRECISION L(*), S(N), W(N), Y(N), Z(N)
+C     DIMENSION L(N*(N+1)/2)
+C
+C--------------------------  PARAMETER USAGE  --------------------------
+C
+C L (I/O) CHOLESKY FACTOR OF HESSIAN, A LOWER TRIANG. MATRIX STORED
+C             COMPACTLY BY ROWS.
+C N (INPUT) ORDER OF  L  AND LENGTH OF  S,  W,  Y,  Z.
+C S (INPUT) THE STEP JUST TAKEN.
+C W (OUTPUT) RIGHT SINGULAR VECTOR OF RANK 1 CORRECTION TO L.
+C Y (INPUT) CHANGE IN GRADIENTS CORRESPONDING TO S.
+C Z (OUTPUT) LEFT SINGULAR VECTOR OF RANK 1 CORRECTION TO L.
+C
+C-------------------------------  NOTES  -------------------------------
+C
+C  ***  ALGORITHM NOTES  ***
+C
+C        WHEN  S  IS COMPUTED IN CERTAIN WAYS, E.G. BY  GQTSTP  OR
+C     DBLDOG,  IT IS POSSIBLE TO SAVE N**2/2 OPERATIONS SINCE  (L**T)*S
+C     OR  L*(L**T)*S IS THEN KNOWN.
+C        IF THE BFGS UPDATE TO L*(L**T) WOULD REDUCE ITS DETERMINANT TO
+C     LESS THAN EPS TIMES ITS OLD VALUE, THEN THIS ROUTINE IN EFFECT
+C     REPLACES  Y  BY  THETA*Y + (1 - THETA)*L*(L**T)*S,  WHERE  THETA
+C     (BETWEEN 0 AND 1) IS CHOSEN TO MAKE THE REDUCTION FACTOR = EPS.
+C
+C  ***  GENERAL  ***
+C
+C     CODED BY DAVID M. GAY (FALL 1979).
+C     THIS SUBROUTINE WAS WRITTEN IN CONNECTION WITH RESEARCH SUPPORTED
+C     BY THE NATIONAL SCIENCE FOUNDATION UNDER GRANTS MCS-7600324 AND
+C     MCS-7906671.
+C
+C------------------------  EXTERNAL QUANTITIES  ------------------------
+C
+C  ***  FUNCTIONS AND SUBROUTINES CALLED  ***
+C
+      DOUBLE PRECISION DD7TPR
+      EXTERNAL DD7TPR, DL7IVM, DL7TVM
+C DD7TPR RETURNS INNER PRODUCT OF TWO VECTORS.
+C DL7IVM MULTIPLIES L**-1 TIMES A VECTOR.
+C DL7TVM MULTIPLIES L**T TIMES A VECTOR.
+C
+C  ***  INTRINSIC FUNCTIONS  ***
+C/+
+      DOUBLE PRECISION DSQRT
+C/
+C--------------------------  LOCAL VARIABLES  --------------------------
+C
+      INTEGER I
+      DOUBLE PRECISION CS, CY, EPS, EPSRT, ONE, SHS, YS, THETA
+C
+C  ***  DATA INITIALIZATIONS  ***
+C
+      PARAMETER (EPS=0.1D+0, ONE=1.D+0)
+C
+C+++++++++++++++++++++++++++++++  BODY  ++++++++++++++++++++++++++++++++
+C
+      CALL DL7TVM(N, W, L, S)
+      SHS = DD7TPR(N, W, W)
+      YS = DD7TPR(N, Y, S)
+      IF (YS .GE. EPS*SHS) GO TO 10
+         THETA = (ONE - EPS) * SHS / (SHS - YS)
+         EPSRT = DSQRT(EPS)
+         CY = THETA / (SHS * EPSRT)
+         CS = (ONE + (THETA-ONE)/EPSRT) / SHS
+         GO TO 20
+ 10   CY = ONE / (DSQRT(YS) * DSQRT(SHS))
+      CS = ONE / SHS
+ 20   CALL DL7IVM(N, Z, L, Y)
+      DO 30 I = 1, N
+ 30      Z(I) = CY * Z(I)  -  CS * W(I)
+C
+      RETURN
+C  ***  LAST CARD OF DW7ZBF FOLLOWS  ***
+      END
+      SUBROUTINE DC7VFN(IV, L, LH, LIV, LV, N, P, V)
+C
+C  ***  FINISH COVARIANCE COMPUTATION FOR  DRN2G,  DRNSG  ***
+C
+      INTEGER LH, LIV, LV, N, P
+      INTEGER IV(LIV)
+      DOUBLE PRECISION L(LH), V(LV)
+C
+      EXTERNAL DL7NVR, DL7TSQ, DV7SCL
+C
+C  ***  LOCAL VARIABLES  ***
+C
+      INTEGER COV, I
+      DOUBLE PRECISION HALF
+C
+C  ***  SUBSCRIPTS FOR IV AND V  ***
+C
+      INTEGER CNVCOD, COVMAT, F, FDH, H, MODE, RDREQ, REGD
+C
+      PARAMETER (CNVCOD=55, COVMAT=26, F=10, FDH=74, H=56, MODE=35,
+     1           RDREQ=57, REGD=67)
+      DATA HALF/0.5D+0/
+C
+C  ***  BODY  ***
+C
+      IV(1) = IV(CNVCOD)
+      I = IV(MODE) - P
+      IV(MODE) = 0
+      IV(CNVCOD) = 0
+      IF (IV(FDH) .LE. 0) GO TO 999
+      IF ((I-2)**2 .EQ. 1) IV(REGD) = 1
+      IF (MOD(IV(RDREQ),2) .NE. 1) GO TO 999
+C
+C     ***  FINISH COMPUTING COVARIANCE MATRIX = INVERSE OF F.D. HESSIAN.
+C
+      COV = IABS(IV(H))
+      IV(FDH) = 0
+C
+      IF (IV(COVMAT) .NE. 0) GO TO 999
+      IF (I .GE. 2) GO TO 10
+         CALL DL7NVR(P, V(COV), L)
+         CALL DL7TSQ(P, V(COV), V(COV))
+C
+ 10   CALL DV7SCL(LH, V(COV), V(F)/(HALF * DBLE(MAX0(1,N-P))), V(COV))
+      IV(COVMAT) = COV
+C
+ 999  RETURN
+C  ***  LAST LINE OF DC7VFN FOLLOWS  ***
+      END
+      SUBROUTINE DD7MLP(N, X, Y, Z, K)
+C
+C ***  SET X = DIAG(Y)**K * Z
+C ***  FOR X, Z = LOWER TRIANG. MATRICES STORED COMPACTLY BY ROW
+C ***  K = 1 OR -1.
+C
+      INTEGER N, K
+      DOUBLE PRECISION X(*), Y(N), Z(*)
+      INTEGER I, J, L
+      DOUBLE PRECISION ONE, T
+      DATA ONE/1.D+0/
+C
+      L = 1
+      IF (K .GE. 0) GO TO 30
+      DO 20 I = 1, N
+         T = ONE / Y(I)
+         DO 10 J = 1, I
+            X(L) = T * Z(L)
+            L = L + 1
+ 10         CONTINUE
+ 20      CONTINUE
+      GO TO 999
+C
+ 30   DO 50 I = 1, N
+         T = Y(I)
+         DO 40 J = 1, I
+            X(L) = T * Z(L)
+            L = L + 1
+ 40         CONTINUE
+ 50      CONTINUE
+ 999  RETURN
+C  ***  LAST CARD OF DD7MLP FOLLOWS  ***
+      END
+      SUBROUTINE DL7IVM(N, X, L, Y)
+C
+C  ***  SOLVE  L*X = Y, WHERE  L  IS AN  N X N  LOWER TRIANGULAR
+C  ***  MATRIX STORED COMPACTLY BY ROWS.  X AND Y MAY OCCUPY THE SAME
+C  ***  STORAGE.  ***
+C
+      INTEGER N
+      DOUBLE PRECISION X(N), L(*), Y(N)
+      DOUBLE PRECISION DD7TPR
+      EXTERNAL DD7TPR
+      INTEGER I, J, K
+      DOUBLE PRECISION T, ZERO
+      PARAMETER (ZERO=0.D+0)
+C
+      DO 10 K = 1, N
+         IF (Y(K) .NE. ZERO) GO TO 20
+         X(K) = ZERO
+ 10      CONTINUE
+      GO TO 999
+ 20   J = K*(K+1)/2
+      X(K) = Y(K) / L(J)
+      IF (K .GE. N) GO TO 999
+      K = K + 1
+      DO 30 I = K, N
+         T = DD7TPR(I-1, L(J+1), X)
+         J = J + I
+         X(I) = (Y(I) - T)/L(J)
+ 30      CONTINUE
+ 999  RETURN
+C  ***  LAST CARD OF DL7IVM FOLLOWS  ***
+      END
+      SUBROUTINE DD7UPD(D, DR, IV, LIV, LV, N, ND, NN, N2, P, V)
+C
+C  ***  UPDATE SCALE VECTOR D FOR NL2IT  ***
+C
+C  ***  PARAMETER DECLARATIONS  ***
+C
+      INTEGER LIV, LV, N, ND, NN, N2, P
+      INTEGER IV(LIV)
+      DOUBLE PRECISION D(P), DR(ND,P), V(LV)
+C     DIMENSION V(*)
+C
+C  ***  LOCAL VARIABLES  ***
+C
+      INTEGER D0, I, JCN0, JCN1, JCNI, JTOL0, JTOLI, K, SII
+      DOUBLE PRECISION T, VDFAC
+C
+C     ***  CONSTANTS  ***
+C
+      DOUBLE PRECISION ZERO
+C
+C  ***  INTRINSIC FUNCTIONS  ***
+C/+
+      DOUBLE PRECISION DSQRT
+C/
+C  ***  EXTERNAL SUBROUTINE  ***
+C
+      EXTERNAL DV7SCP
+C
+C DV7SCP... SETS ALL COMPONENTS OF A VECTOR TO A SCALAR.
+C
+C  ***  SUBSCRIPTS FOR IV AND V  ***
+C
+      INTEGER DFAC, DTYPE, JCN, JTOL, NITER, S
+      PARAMETER (DFAC=41, DTYPE=16, JCN=66, JTOL=59, NITER=31, S=62)
+C
+      PARAMETER (ZERO=0.D+0)
+C
+C-------------------------------  BODY  --------------------------------
+C
+      IF (IV(DTYPE) .NE. 1 .AND. IV(NITER) .GT. 0) GO TO 999
+      JCN1 = IV(JCN)
+      JCN0 = IABS(JCN1) - 1
+      IF (JCN1 .LT. 0) GO TO 10
+         IV(JCN) = -JCN1
+         CALL DV7SCP(P, V(JCN1), ZERO)
+ 10   DO 30 I = 1, P
+         JCNI = JCN0 + I
+         T  = V(JCNI)
+         DO 20 K = 1, NN
+ 20           T = DMAX1(T, DABS(DR(K,I)))
+         V(JCNI) = T
+ 30      CONTINUE
+      IF (N2 .LT. N) GO TO 999
+      VDFAC = V(DFAC)
+      JTOL0 = IV(JTOL) - 1
+      D0 = JTOL0 + P
+      SII = IV(S) - 1
+      DO 50 I = 1, P
+         SII = SII + I
+         JCNI = JCN0 + I
+         T = V(JCNI)
+         IF (V(SII) .GT. ZERO) T = DMAX1(DSQRT(V(SII)), T)
+         JTOLI = JTOL0 + I
+         D0 = D0 + 1
+         IF (T .LT. V(JTOLI)) T = DMAX1(V(D0), V(JTOLI))
+         D(I) = DMAX1(VDFAC*D(I), T)
+ 50      CONTINUE
+C
+ 999  RETURN
+C  ***  LAST CARD OF DD7UPD FOLLOWS  ***
+      END
+      SUBROUTINE DV7SHF(N, K, X)
+C
+C  ***  SHIFT X(K),...,X(N) LEFT CIRCULARLY ONE POSITION  ***
+C
+      INTEGER N, K
+      DOUBLE PRECISION X(N)
+C
+      INTEGER I, NM1
+      DOUBLE PRECISION T
+C
+      IF (K .GE. N) GO TO 999
+      NM1 = N - 1
+      T = X(K)
+      DO 10 I = K, NM1
+ 10      X(I) = X(I+1)
+      X(N) = T
+ 999  RETURN
+      END
+      SUBROUTINE DS3GRD(ALPHA, B, D, ETA0, FX, G, IRC, P, W, X)
+C
+C  ***  COMPUTE FINITE DIFFERENCE GRADIENT BY STWEART*S SCHEME  ***
+C
+C     ***  PARAMETERS  ***
+C
+      INTEGER IRC, P
+      DOUBLE PRECISION ALPHA(P), B(2,P), D(P), ETA0, FX, G(P), W(6),
+     1                 X(P)
+C
+C.......................................................................
+C
+C     ***  PURPOSE  ***
+C
+C        THIS SUBROUTINE USES AN EMBELLISHED FORM OF THE FINITE-DIFFER-
+C     ENCE SCHEME PROPOSED BY STEWART (REF. 1) TO APPROXIMATE THE
+C     GRADIENT OF THE FUNCTION F(X), WHOSE VALUES ARE SUPPLIED BY
+C     REVERSE COMMUNICATION.
+C
+C     ***  PARAMETER DESCRIPTION  ***
+C
+C  ALPHA IN  (APPROXIMATE) DIAGONAL ELEMENTS OF THE HESSIAN OF F(X).
+C      B IN  ARRAY OF SIMPLE LOWER AND UPPER BOUNDS ON X.  X MUST
+C             SATISFY B(1,I) .LE. X(I) .LE. B(2,I), I = 1(1)P.
+C             FOR ALL I WITH B(1,I) .GE. B(2,I), DS3GRD SIMPLY
+C             SETS G(I) TO 0.
+C      D IN  SCALE VECTOR SUCH THAT D(I)*X(I), I = 1,...,P, ARE IN
+C             COMPARABLE UNITS.
+C   ETA0 IN  ESTIMATED BOUND ON RELATIVE ERROR IN THE FUNCTION VALUE...
+C             (TRUE VALUE) = (COMPUTED VALUE)*(1+E),   WHERE
+C             ABS(E) .LE. ETA0.
+C     FX I/O ON INPUT,  FX  MUST BE THE COMPUTED VALUE OF F(X).  ON
+C             OUTPUT WITH IRC = 0, FX HAS BEEN RESTORED TO ITS ORIGINAL
+C             VALUE, THE ONE IT HAD WHEN DS3GRD WAS LAST CALLED WITH
+C             IRC = 0.
+C      G I/O ON INPUT WITH IRC = 0, G SHOULD CONTAIN AN APPROXIMATION
+C             TO THE GRADIENT OF F NEAR X, E.G., THE GRADIENT AT THE
+C             PREVIOUS ITERATE.  WHEN DS3GRD RETURNS WITH IRC = 0, G IS
+C             THE DESIRED FINITE-DIFFERENCE APPROXIMATION TO THE
+C             GRADIENT AT X.
+C    IRC I/O INPUT/RETURN CODE... BEFORE THE VERY FIRST CALL ON DS3GRD,
+C             THE CALLER MUST SET IRC TO 0.  WHENEVER DS3GRD RETURNS A
+C             NONZERO VALUE (OF AT MOST P) FOR IRC, IT HAS PERTURBED
+C             SOME COMPONENT OF X... THE CALLER SHOULD EVALUATE F(X)
+C             AND CALL DS3GRD AGAIN WITH FX = F(X).  IF B PREVENTS
+C             ESTIMATING G(I) I.E., IF THERE IS AN I WITH
+C             B(1,I) .LT. B(2,I) BUT WITH B(1,I) SO CLOSE TO B(2,I)
+C             THAT THE FINITE-DIFFERENCING STEPS CANNOT BE CHOSEN,
+C             THEN DS3GRD RETURNS WITH IRC .GT. P.
+C      P IN  THE NUMBER OF VARIABLES (COMPONENTS OF X) ON WHICH F
+C             DEPENDS.
+C      X I/O ON INPUT WITH IRC = 0, X IS THE POINT AT WHICH THE
+C             GRADIENT OF F IS DESIRED.  ON OUTPUT WITH IRC NONZERO, X
+C             IS THE POINT AT WHICH F SHOULD BE EVALUATED.  ON OUTPUT
+C             WITH IRC = 0, X HAS BEEN RESTORED TO ITS ORIGINAL VALUE
+C             (THE ONE IT HAD WHEN DS3GRD WAS LAST CALLED WITH IRC = 0)
+C             AND G CONTAINS THE DESIRED GRADIENT APPROXIMATION.
+C      W I/O WORK VECTOR OF LENGTH 6 IN WHICH DS3GRD SAVES CERTAIN
+C             QUANTITIES WHILE THE CALLER IS EVALUATING F(X) AT A
+C             PERTURBED X.
+C
+C     ***  APPLICATION AND USAGE RESTRICTIONS  ***
+C
+C        THIS ROUTINE IS INTENDED FOR USE WITH QUASI-NEWTON ROUTINES
+C     FOR UNCONSTRAINED MINIMIZATION (IN WHICH CASE  ALPHA  COMES FROM
+C     THE DIAGONAL OF THE QUASI-NEWTON HESSIAN APPROXIMATION).
+C
+C     ***  ALGORITHM NOTES  ***
+C
+C        THIS CODE DEPARTS FROM THE SCHEME PROPOSED BY STEWART (REF. 1)
+C     IN ITS GUARDING AGAINST OVERLY LARGE OR SMALL STEP SIZES AND ITS
+C     HANDLING OF SPECIAL CASES (SUCH AS ZERO COMPONENTS OF ALPHA OR G).
+C
+C     ***  REFERENCES  ***
+C
+C 1. STEWART, G.W. (1967), A MODIFICATION OF DAVIDON*S MINIMIZATION
+C        METHOD TO ACCEPT DIFFERENCE APPROXIMATIONS OF DERIVATIVES,
+C        J. ASSOC. COMPUT. MACH. 14, PP. 72-83.
+C
+C     ***  HISTORY  ***
+C
+C     DESIGNED AND CODED BY DAVID M. GAY (SUMMER 1977/SUMMER 1980).
+C
+C     ***  GENERAL  ***
+C
+C        THIS ROUTINE WAS PREPARED IN CONNECTION WITH WORK SUPPORTED BY
+C     THE NATIONAL SCIENCE FOUNDATION UNDER GRANTS MCS76-00324 AND
+C     MCS-7906671.
+C
+C.......................................................................
+C
+C     *****  EXTERNAL FUNCTION  *****
+C
+      DOUBLE PRECISION DR7MDC
+      EXTERNAL DR7MDC
+C DR7MDC... RETURNS MACHINE-DEPENDENT CONSTANTS.
+C
+C     ***** INTRINSIC FUNCTIONS *****
+C/+
+      DOUBLE PRECISION DSQRT
+C/
+C     ***** LOCAL VARIABLES *****
+C
+      LOGICAL HIT
+      INTEGER FH, FX0, HSAVE, I, XISAVE
+      DOUBLE PRECISION AAI, AFX, AFXETA, AGI, ALPHAI, AXI, AXIBAR,
+     1                 DISCON, ETA, GI, H, HMIN, XI, XIH
+      DOUBLE PRECISION C2000, FOUR, HMAX0, HMIN0, H0, MACHEP, ONE, P002,
+     1                 THREE, TWO, ZERO
+C
+      PARAMETER (C2000=2.0D+3, FOUR=4.0D+0, HMAX0=0.02D+0, HMIN0=5.0D+1,
+     1     ONE=1.0D+0, P002=0.002D+0, THREE=3.0D+0,
+     2     TWO=2.0D+0, ZERO=0.0D+0)
+      PARAMETER (FH=3, FX0=4, HSAVE=5, XISAVE=6)
+C
+C---------------------------------  BODY  ------------------------------
+C
+      IF (IRC .LT. 0) GO TO 80
+      IF (IRC .GT. 0) GO TO 210
+C
+C     ***  FRESH START -- GET MACHINE-DEPENDENT CONSTANTS  ***
+C
+C     STORE MACHEP IN W(1) AND H0 IN W(2), WHERE MACHEP IS THE UNIT
+C     ROUNDOFF (THE SMALLEST POSITIVE NUMBER SUCH THAT
+C     1 + MACHEP .GT. 1  AND  1 - MACHEP .LT. 1),  AND  H0 IS THE
+C     SQUARE-ROOT OF MACHEP.
+C
+      W(1) = DR7MDC(3)
+      W(2) = DSQRT(W(1))
+C
+      W(FX0) = FX
+C
+C     ***  INCREMENT  I  AND START COMPUTING  G(I)  ***
+C
+ 20   I = IABS(IRC) + 1
+      IF (I .GT. P) GO TO 220
+         IRC = I
+         IF (B(1,I) .LT. B(2,I)) GO TO 30
+            G(I) = ZERO
+            GO TO 20
+ 30      AFX = DABS(W(FX0))
+         MACHEP = W(1)
+         H0 = W(2)
+         HMIN = HMIN0 * MACHEP
+         XI = X(I)
+         W(XISAVE) = XI
+         AXI = DABS(XI)
+         AXIBAR = DMAX1(AXI, ONE/D(I))
+         GI = G(I)
+         AGI = DABS(GI)
+         ETA = DABS(ETA0)
+         IF (AFX .GT. ZERO) ETA = DMAX1(ETA, AGI*AXI*MACHEP/AFX)
+         ALPHAI = ALPHA(I)
+         IF (ALPHAI .EQ. ZERO) GO TO 130
+         IF (GI .EQ. ZERO .OR. FX .EQ. ZERO) GO TO 140
+         AFXETA = AFX*ETA
+         AAI = DABS(ALPHAI)
+C
+C        *** COMPUTE H = STEWART*S FORWARD-DIFFERENCE STEP SIZE.
+C
+         IF (GI**2 .LE. AFXETA*AAI) GO TO 40
+              H = TWO*DSQRT(AFXETA/AAI)
+              H = H*(ONE - AAI*H/(THREE*AAI*H + FOUR*AGI))
+              GO TO 50
+C40      H = TWO*(AFXETA*AGI/(AAI**2))**(ONE/THREE)
+ 40      H = TWO * (AFXETA*AGI)**(ONE/THREE) * AAI**(-TWO/THREE)
+         H = H*(ONE - TWO*AGI/(THREE*AAI*H + FOUR*AGI))
+C
+C        ***  ENSURE THAT  H  IS NOT INSIGNIFICANTLY SMALL  ***
+C
+ 50      H = DMAX1(H, HMIN*AXIBAR)
+C
+C        *** USE FORWARD DIFFERENCE IF BOUND ON TRUNCATION ERROR IS AT
+C        *** MOST 10**-3.
+C
+         IF (AAI*H .LE. P002*AGI) GO TO 120
+C
+C        *** COMPUTE H = STEWART*S STEP FOR CENTRAL DIFFERENCE.
+C
+         DISCON = C2000*AFXETA
+         H = DISCON/(AGI + DSQRT(GI**2 + AAI*DISCON))
+C
+C        ***  ENSURE THAT  H  IS NEITHER TOO SMALL NOR TOO BIG  ***
+C
+         H = DMAX1(H, HMIN*AXIBAR)
+         IF (H .GE. HMAX0*AXIBAR) H = AXIBAR * H0**(TWO/THREE)
+C
+C        ***  COMPUTE CENTRAL DIFFERENCE  ***
+C
+         XIH = XI + H
+         IF (XI - H .LT. B(1,I)) GO TO 60
+         IRC = -I
+         IF (XIH .LE. B(2,I)) GO TO 200
+            H = -H
+            XIH = XI + H
+            IF (XI + TWO*H .LT. B(1,I)) GO TO 190
+            GO TO 70
+ 60      IF (XI + TWO*H .GT. B(2,I)) GO TO 190
+C        *** MUST DO OFF-SIDE CENTRAL DIFFERENCE ***
+ 70      IRC = -(I + P)
+         GO TO 200
+C
+ 80      I = -IRC
+         IF (I .LE. P) GO TO 100
+         I = I - P
+         IF (I .GT. P) GO TO 90
+         W(FH) = FX
+         H = TWO * W(HSAVE)
+         XIH = W(XISAVE) + H
+         IRC = IRC - P
+         GO TO 200
+C
+C    *** FINISH OFF-SIDE CENTRAL DIFFERENCE ***
+C
+ 90      I = I - P
+         G(I) = (FOUR*W(FH) - FX - THREE*W(FX0)) / W(HSAVE)
+         IRC = I
+         X(I) = W(XISAVE)
+         GO TO 20
+C
+ 100     H = -W(HSAVE)
+         IF (H .GT. ZERO) GO TO 110
+         W(FH) = FX
+         XIH = W(XISAVE) + H
+         GO TO 200
+C
+ 110     G(I) = (W(FH) - FX) / (TWO * H)
+         X(I) = W(XISAVE)
+         GO TO 20
+C
+C     ***  COMPUTE FORWARD DIFFERENCES IN VARIOUS CASES  ***
+C
+ 120     IF (H .GE. HMAX0*AXIBAR) H = H0 * AXIBAR
+         IF (ALPHAI*GI .LT. ZERO) H = -H
+         GO TO 150
+ 130     H = AXIBAR
+         GO TO 150
+ 140     H = H0 * AXIBAR
+C
+ 150     HIT = .FALSE.
+ 160     XIH = XI + H
+         IF (H .GT. ZERO) GO TO 170
+            IF (XIH .GE. B(1,I)) GO TO 200
+            GO TO 180
+ 170     IF (XIH .LE. B(2,I)) GO TO 200
+ 180        IF (HIT) GO TO 190
+            HIT = .TRUE.
+            H = -H
+            GO TO 160
+C
+C        *** ERROR RETURN...
+ 190     IRC = I + P
+         GO TO 230
+C
+C        *** RETURN FOR NEW FUNCTION VALUE...
+ 200     X(I) = XIH
+         W(HSAVE) = H
+         GO TO 999
+C
+C     ***  COMPUTE ACTUAL FORWARD DIFFERENCE  ***
+C
+ 210     G(IRC) = (FX - W(FX0)) / W(HSAVE)
+         X(IRC) = W(XISAVE)
+         GO TO 20
+C
+C  ***  RESTORE FX AND INDICATE THAT G HAS BEEN COMPUTED  ***
+C
+ 220  IRC = 0
+ 230  FX = W(FX0)
+C
+ 999  RETURN
+C  ***  LAST LINE OF DS3GRD FOLLOWS  ***
+      END
+      SUBROUTINE DL7UPD(BETA, GAMMA, L, LAMBDA, LPLUS, N, W, Z)
+C
+C  ***  COMPUTE LPLUS = SECANT UPDATE OF L  ***
+C
+C  ***  PARAMETER DECLARATIONS  ***
+C
+      INTEGER N
+      DOUBLE PRECISION BETA(N), GAMMA(N), L(*), LAMBDA(N), LPLUS(*),
+     1                 W(N), Z(N)
+C     DIMENSION L(N*(N+1)/2), LPLUS(N*(N+1)/2)
+C
+C--------------------------  PARAMETER USAGE  --------------------------
+C
+C   BETA = SCRATCH VECTOR.
+C  GAMMA = SCRATCH VECTOR.
+C      L (INPUT) LOWER TRIANGULAR MATRIX, STORED ROWWISE.
+C LAMBDA = SCRATCH VECTOR.
+C  LPLUS (OUTPUT) LOWER TRIANGULAR MATRIX, STORED ROWWISE, WHICH MAY
+C             OCCUPY THE SAME STORAGE AS  L.
+C      N (INPUT) LENGTH OF VECTOR PARAMETERS AND ORDER OF MATRICES.
+C      W (INPUT, DESTROYED ON OUTPUT) RIGHT SINGULAR VECTOR OF RANK 1
+C             CORRECTION TO  L.
+C      Z (INPUT, DESTROYED ON OUTPUT) LEFT SINGULAR VECTOR OF RANK 1
+C             CORRECTION TO  L.
+C
+C-------------------------------  NOTES  -------------------------------
+C
+C  ***  APPLICATION AND USAGE RESTRICTIONS  ***
+C
+C        THIS ROUTINE UPDATES THE CHOLESKY FACTOR  L  OF A SYMMETRIC
+C     POSITIVE DEFINITE MATRIX TO WHICH A SECANT UPDATE IS BEING
+C     APPLIED -- IT COMPUTES A CHOLESKY FACTOR  LPLUS  OF
+C     L * (I + Z*W**T) * (I + W*Z**T) * L**T.  IT IS ASSUMED THAT  W
+C     AND  Z  HAVE BEEN CHOSEN SO THAT THE UPDATED MATRIX IS STRICTLY
+C     POSITIVE DEFINITE.
+C
+C  ***  ALGORITHM NOTES  ***
+C
+C        THIS CODE USES RECURRENCE 3 OF REF. 1 (WITH D(J) = 1 FOR ALL J)
+C     TO COMPUTE  LPLUS  OF THE FORM  L * (I + Z*W**T) * Q,  WHERE  Q
+C     IS AN ORTHOGONAL MATRIX THAT MAKES THE RESULT LOWER TRIANGULAR.
+C        LPLUS MAY HAVE SOME NEGATIVE DIAGONAL ELEMENTS.
+C
+C  ***  REFERENCES  ***
+C
+C 1.  GOLDFARB, D. (1976), FACTORIZED VARIABLE METRIC METHODS FOR UNCON-
+C             STRAINED OPTIMIZATION, MATH. COMPUT. 30, PP. 796-811.
+C
+C  ***  GENERAL  ***
+C
+C     CODED BY DAVID M. GAY (FALL 1979).
+C     THIS SUBROUTINE WAS WRITTEN IN CONNECTION WITH RESEARCH SUPPORTED
+C     BY THE NATIONAL SCIENCE FOUNDATION UNDER GRANTS MCS-7600324 AND
+C     MCS-7906671.
+C
+C------------------------  EXTERNAL QUANTITIES  ------------------------
+C
+C  ***  INTRINSIC FUNCTIONS  ***
+C/+
+      DOUBLE PRECISION DSQRT
+C/
+C--------------------------  LOCAL VARIABLES  --------------------------
+C
+      INTEGER I, IJ, J, JJ, JP1, K, NM1, NP1
+      DOUBLE PRECISION A, B, BJ, ETA, GJ, LJ, LIJ, LJJ, NU, S, THETA,
+     1                 WJ, ZJ
+      DOUBLE PRECISION ONE, ZERO
+C
+C  ***  DATA INITIALIZATIONS  ***
+C
+      PARAMETER (ONE=1.D+0, ZERO=0.D+0)
+C
+C+++++++++++++++++++++++++++++++  BODY  ++++++++++++++++++++++++++++++++
+C
+      NU = ONE
+      ETA = ZERO
+      IF (N .LE. 1) GO TO 30
+      NM1 = N - 1
+C
+C  ***  TEMPORARILY STORE S(J) = SUM OVER K = J+1 TO N OF W(K)**2 IN
+C  ***  LAMBDA(J).
+C
+      S = ZERO
+      DO 10 I = 1, NM1
+         J = N - I
+         S = S + W(J+1)**2
+         LAMBDA(J) = S
+ 10      CONTINUE
+C
+C  ***  COMPUTE LAMBDA, GAMMA, AND BETA BY GOLDFARB*S RECURRENCE 3.
+C
+      DO 20 J = 1, NM1
+         WJ = W(J)
+         A = NU*Z(J) - ETA*WJ
+         THETA = ONE + A*WJ
+         S = A*LAMBDA(J)
+         LJ = DSQRT(THETA**2 + A*S)
+         IF (THETA .GT. ZERO) LJ = -LJ
+         LAMBDA(J) = LJ
+         B = THETA*WJ + S
+         GAMMA(J) = B * NU / LJ
+         BETA(J) = (A - B*ETA) / LJ
+         NU = -NU / LJ
+         ETA = -(ETA + (A**2)/(THETA - LJ)) / LJ
+ 20      CONTINUE
+ 30   LAMBDA(N) = ONE + (NU*Z(N) - ETA*W(N))*W(N)
+C
+C  ***  UPDATE L, GRADUALLY OVERWRITING  W  AND  Z  WITH  L*W  AND  L*Z.
+C
+      NP1 = N + 1
+      JJ = N * (N + 1) / 2
+      DO 60 K = 1, N
+         J = NP1 - K
+         LJ = LAMBDA(J)
+         LJJ = L(JJ)
+         LPLUS(JJ) = LJ * LJJ
+         WJ = W(J)
+         W(J) = LJJ * WJ
+         ZJ = Z(J)
+         Z(J) = LJJ * ZJ
+         IF (K .EQ. 1) GO TO 50
+         BJ = BETA(J)
+         GJ = GAMMA(J)
+         IJ = JJ + J
+         JP1 = J + 1
+         DO 40 I = JP1, N
+              LIJ = L(IJ)
+              LPLUS(IJ) = LJ*LIJ + BJ*W(I) + GJ*Z(I)
+              W(I) = W(I) + LIJ*WJ
+              Z(I) = Z(I) + LIJ*ZJ
+              IJ = IJ + I
+ 40           CONTINUE
+ 50      JJ = JJ - J
+ 60      CONTINUE
+C
+      RETURN
+C  ***  LAST CARD OF DL7UPD FOLLOWS  ***
+      END
+      SUBROUTINE DO7PRD(L, LS, P, S, W, Y, Z)
+C
+C  ***  FOR I = 1..L, SET S = S + W(I)*Y(.,I)*(Z(.,I)**T), I.E.,
+C  ***        ADD W(I) TIMES THE OUTER PRODUCT OF Y(.,I) AND Z(.,I).
+C
+      INTEGER L, LS, P
+      DOUBLE PRECISION S(LS), W(L), Y(P,L), Z(P,L)
+C     DIMENSION S(P*(P+1)/2)
+C
+      INTEGER I, J, K, M
+      DOUBLE PRECISION WK, YI, ZERO
+      DATA ZERO/0.D+0/
+C
+      DO 30 K = 1, L
+         WK = W(K)
+         IF (WK .EQ. ZERO) GO TO 30
+         M = 1
+         DO 20 I = 1, P
+              YI = WK * Y(I,K)
+              DO 10 J = 1, I
+                   S(M) = S(M) + YI*Z(J,K)
+                   M = M + 1
+ 10                CONTINUE
+ 20           CONTINUE
+ 30      CONTINUE
+C
+      RETURN
+C  ***  LAST CARD OF DO7PRD FOLLOWS  ***
+      END
+      SUBROUTINE DV7VMP(N, X, Y, Z, K)
+C
+C ***  SET X(I) = Y(I) * Z(I)**K, 1 .LE. I .LE. N (FOR K = 1 OR -1)  ***
+C
+      INTEGER N, K
+      DOUBLE PRECISION X(N), Y(N), Z(N)
+      INTEGER I
+C
+      IF (K .GE. 0) GO TO 20
+      DO 10 I = 1, N
+ 10      X(I) = Y(I) / Z(I)
+      GO TO 999
+C
+ 20   DO 30 I = 1, N
+ 30      X(I) = Y(I) * Z(I)
+ 999  RETURN
+C  ***  LAST CARD OF DV7VMP FOLLOWS  ***
+      END
+      SUBROUTINE DSM(M,N,NPAIRS,INDROW,INDCOL,NGRP,MAXGRP,MINGRP,
+     *               INFO,IPNTR,JPNTR,IWA,LIWA,BWA)
+      INTEGER M,N,NPAIRS,MAXGRP,MINGRP,INFO,LIWA
+      INTEGER INDROW(NPAIRS),INDCOL(NPAIRS),NGRP(N),
+     *        IPNTR(1),JPNTR(1),IWA(LIWA)
+      LOGICAL BWA(N)
+C     **********
+C
+C     SUBROUTINE DSM
+C
+C     THE PURPOSE OF DSM IS TO DETERMINE AN OPTIMAL OR NEAR-
+C     OPTIMAL CONSISTENT PARTITION OF THE COLUMNS OF A SPARSE
+C     M BY N MATRIX A.
+C
+C     THE SPARSITY PATTERN OF THE MATRIX A IS SPECIFIED BY
+C     THE ARRAYS INDROW AND INDCOL. ON INPUT THE INDICES
+C     FOR THE NON-ZERO ELEMENTS OF A ARE
+C
+C           INDROW(K),INDCOL(K), K = 1,2,...,NPAIRS.
+C
+C     THE (INDROW,INDCOL) PAIRS MAY BE SPECIFIED IN ANY ORDER.
+C     DUPLICATE INPUT PAIRS ARE PERMITTED, BUT THE SUBROUTINE
+C     ELIMINATES THEM.
+C
+C     THE SUBROUTINE PARTITIONS THE COLUMNS OF A INTO GROUPS
+C     SUCH THAT COLUMNS IN THE SAME GROUP DO NOT HAVE A
+C     NON-ZERO IN THE SAME ROW POSITION. A PARTITION OF THE
+C     COLUMNS OF A WITH THIS PROPERTY IS CONSISTENT WITH THE
+C     DIRECT DETERMINATION OF A.
+C
+C     THE SUBROUTINE STATEMENT IS
+C
+C       SUBROUTINE DSM(M,N,NPAIRS,INDROW,INDCOL,NGRP,MAXGRP,MINGRP,
+C                      INFO,IPNTR,JPNTR,IWA,LIWA,BWA)
+C
+C     WHERE
+C
+C       M IS A POSITIVE INTEGER INPUT VARIABLE SET TO THE NUMBER
+C         OF ROWS OF A.
+C
+C       N IS A POSITIVE INTEGER INPUT VARIABLE SET TO THE NUMBER
+C         OF COLUMNS OF A.
+C
+C       NPAIRS IS A POSITIVE INTEGER INPUT VARIABLE SET TO THE
+C         NUMBER OF (INDROW,INDCOL) PAIRS USED TO DESCRIBE THE
+C         SPARSITY PATTERN OF A.
+C
+C       INDROW IS AN INTEGER ARRAY OF LENGTH NPAIRS. ON INPUT INDROW
+C         MUST CONTAIN THE ROW INDICES OF THE NON-ZERO ELEMENTS OF A.
+C         ON OUTPUT INDROW IS PERMUTED SO THAT THE CORRESPONDING
+C         COLUMN INDICES ARE IN NON-DECREASING ORDER. THE COLUMN
+C         INDICES CAN BE RECOVERED FROM THE ARRAY JPNTR.
+C
+C       INDCOL IS AN INTEGER ARRAY OF LENGTH NPAIRS. ON INPUT INDCOL
+C         MUST CONTAIN THE COLUMN INDICES OF THE NON-ZERO ELEMENTS OF
+C         A. ON OUTPUT INDCOL IS PERMUTED SO THAT THE CORRESPONDING
+C         ROW INDICES ARE IN NON-DECREASING ORDER. THE ROW INDICES
+C         CAN BE RECOVERED FROM THE ARRAY IPNTR.
+C
+C       NGRP IS AN INTEGER OUTPUT ARRAY OF LENGTH N WHICH SPECIFIES
+C         THE PARTITION OF THE COLUMNS OF A. COLUMN JCOL BELONGS
+C         TO GROUP NGRP(JCOL).
+C
+C       MAXGRP IS AN INTEGER OUTPUT VARIABLE WHICH SPECIFIES THE
+C         NUMBER OF GROUPS IN THE PARTITION OF THE COLUMNS OF A.
+C
+C       MINGRP IS AN INTEGER OUTPUT VARIABLE WHICH SPECIFIES A LOWER
+C         BOUND FOR THE NUMBER OF GROUPS IN ANY CONSISTENT PARTITION
+C         OF THE COLUMNS OF A.
+C
+C       INFO IS AN INTEGER OUTPUT VARIABLE SET AS FOLLOWS. FOR
+C         NORMAL TERMINATION INFO = 1. IF M, N, OR NPAIRS IS NOT
+C         POSITIVE OR LIWA IS LESS THAN MAX(M,6*N), THEN INFO = 0.
+C         IF THE K-TH ELEMENT OF INDROW IS NOT AN INTEGER BETWEEN
+C         1 AND M OR THE K-TH ELEMENT OF INDCOL IS NOT AN INTEGER
+C         BETWEEN 1 AND N, THEN INFO = -K.
+C
+C       IPNTR IS AN INTEGER OUTPUT ARRAY OF LENGTH M + 1 WHICH
+C         SPECIFIES THE LOCATIONS OF THE COLUMN INDICES IN INDCOL.
+C         THE COLUMN INDICES FOR ROW I ARE
+C
+C               INDCOL(K), K = IPNTR(I),...,IPNTR(I+1)-1.
+C
+C         NOTE THAT IPNTR(M+1)-1 IS THEN THE NUMBER OF NON-ZERO
+C         ELEMENTS OF THE MATRIX A.
+C
+C       JPNTR IS AN INTEGER OUTPUT ARRAY OF LENGTH N + 1 WHICH
+C         SPECIFIES THE LOCATIONS OF THE ROW INDICES IN INDROW.
+C         THE ROW INDICES FOR COLUMN J ARE
+C
+C               INDROW(K), K = JPNTR(J),...,JPNTR(J+1)-1.
+C
+C         NOTE THAT JPNTR(N+1)-1 IS THEN THE NUMBER OF NON-ZERO
+C         ELEMENTS OF THE MATRIX A.
+C
+C       IWA IS AN INTEGER WORK ARRAY OF LENGTH LIWA.
+C
+C       LIWA IS A POSITIVE INTEGER INPUT VARIABLE NOT LESS THAN
+C         MAX(M,6*N).
+C
+C       BWA IS A LOGICAL WORK ARRAY OF LENGTH N.
+C
+C     SUBPROGRAMS CALLED
+C
+C       MINPACK-SUPPLIED ...D7EGR,I7DO,N7MSRT,M7SEQ,S7ETR,M7SLO,S7RTDT
+C
+C       FORTRAN-SUPPLIED ... MAX0
+C
+C     ARGONNE NATIONAL LABORATORY. MINPACK PROJECT. JUNE 1982.
+C     THOMAS F. COLEMAN, BURTON S. GARBOW, JORGE J. MORE
+C
+C     **********
+      INTEGER I,IR,J,JP,JPL,JPU,K,MAXCLQ,NNZ,NUMGRP
+C
+C     CHECK THE INPUT DATA.
+C
+      INFO = 0
+      IF (M .LT. 1 .OR. N .LT. 1 .OR. NPAIRS .LT. 1 .OR.
+     *    LIWA .LT. MAX0(M,6*N)) GO TO 130
+      DO 10 K = 1, NPAIRS
+         INFO = -K
+         IF (INDROW(K) .LT. 1 .OR. INDROW(K) .GT. M .OR.
+     *       INDCOL(K) .LT. 1 .OR. INDCOL(K) .GT. N) GO TO 130
+   10    CONTINUE
+      INFO = 1
+C
+C     SORT THE DATA STRUCTURE BY COLUMNS.
+C
+      CALL S7RTDT(N,NPAIRS,INDROW,INDCOL,JPNTR,IWA(1))
+C
+C     COMPRESS THE DATA AND DETERMINE THE NUMBER OF
+C     NON-ZERO ELEMENTS OF A.
+C
+      DO 20 I = 1, M
+         IWA(I) = 0
+   20    CONTINUE
+      NNZ = 0
+      DO 70 J = 1, N
+         JPL = JPNTR(J)
+         JPU = JPNTR(J+1) - 1
+         JPNTR(J) = NNZ + 1
+         IF (JPU .LT. JPL) GO TO 60
+         DO 40 JP = JPL, JPU
+            IR = INDROW(JP)
+            IF (IWA(IR) .NE. 0) GO TO 30
+            NNZ = NNZ + 1
+            INDROW(NNZ) = IR
+            IWA(IR) = 1
+   30       CONTINUE
+   40       CONTINUE
+         JPL = JPNTR(J)
+         DO 50 JP = JPL, NNZ
+            IR = INDROW(JP)
+            IWA(IR) = 0
+   50       CONTINUE
+   60    CONTINUE
+   70    CONTINUE
+      JPNTR(N+1) = NNZ + 1
+C
+C     EXTEND THE DATA STRUCTURE TO ROWS.
+C
+      CALL S7ETR(M,N,INDROW,JPNTR,INDCOL,IPNTR,IWA(1))
+C
+C     DETERMINE A LOWER BOUND FOR THE NUMBER OF GROUPS.
+C
+      MINGRP = 0
+      DO 80 I = 1, M
+         MINGRP = MAX0(MINGRP,IPNTR(I+1)-IPNTR(I))
+   80    CONTINUE
+C
+C     DETERMINE THE DEGREE SEQUENCE FOR THE INTERSECTION
+C     GRAPH OF THE COLUMNS OF A.
+C
+      CALL D7EGR(N,INDROW,JPNTR,INDCOL,IPNTR,IWA(5*N+1),IWA(N+1),BWA)
+C
+C     COLOR THE INTERSECTION GRAPH OF THE COLUMNS OF A
+C     WITH THE SMALLEST-LAST (SL) ORDERING.
+C
+      CALL M7SLO(N,INDROW,JPNTR,INDCOL,IPNTR,IWA(5*N+1),IWA(4*N+1),
+     *         MAXCLQ,IWA(1),IWA(N+1),IWA(2*N+1),IWA(3*N+1),BWA)
+      CALL M7SEQ(N,INDROW,JPNTR,INDCOL,IPNTR,IWA(4*N+1),NGRP,MAXGRP,
+     *         IWA(N+1),BWA)
+      MINGRP = MAX0(MINGRP,MAXCLQ)
+      IF (MAXGRP .EQ. MINGRP) GO TO 130
+C
+C     COLOR THE INTERSECTION GRAPH OF THE COLUMNS OF A
+C     WITH THE INCIDENCE-DEGREE (ID) ORDERING.
+C
+      CALL I7DO(M,N,INDROW,JPNTR,INDCOL,IPNTR,IWA(5*N+1),IWA(4*N+1),
+     *         MAXCLQ,IWA(1),IWA(N+1),IWA(2*N+1),IWA(3*N+1),BWA)
+      CALL M7SEQ(N,INDROW,JPNTR,INDCOL,IPNTR,IWA(4*N+1),IWA(1),NUMGRP,
+     *         IWA(N+1),BWA)
+      MINGRP = MAX0(MINGRP,MAXCLQ)
+      IF (NUMGRP .GE. MAXGRP) GO TO 100
+      MAXGRP = NUMGRP
+      DO 90 J = 1, N
+         NGRP(J) = IWA(J)
+   90    CONTINUE
+      IF (MAXGRP .EQ. MINGRP) GO TO 130
+  100 CONTINUE
+C
+C     COLOR THE INTERSECTION GRAPH OF THE COLUMNS OF A
+C     WITH THE LARGEST-FIRST (LF) ORDERING.
+C
+      CALL N7MSRT(N,N-1,IWA(5*N+1),-1,IWA(4*N+1),IWA(2*N+1),IWA(N+1))
+      CALL M7SEQ(N,INDROW,JPNTR,INDCOL,IPNTR,IWA(4*N+1),IWA(1),NUMGRP,
+     *         IWA(N+1),BWA)
+      IF (NUMGRP .GE. MAXGRP) GO TO 120
+      MAXGRP = NUMGRP
+      DO 110 J = 1, N
+         NGRP(J) = IWA(J)
+  110    CONTINUE
+  120 CONTINUE
+C
+C     EXIT FROM PROGRAM.
+C
+  130 CONTINUE
+      RETURN
+C
+C     LAST CARD OF SUBROUTINE DSM.
+C
+      END
+      SUBROUTINE M7SEQ(N,INDROW,JPNTR,INDCOL,IPNTR,LIST,NGRP,MAXGRP,
+     *               IWA,BWA)
+      INTEGER N,MAXGRP
+      INTEGER INDROW(1),JPNTR(1),INDCOL(1),IPNTR(1),LIST(N),NGRP(N),
+     *        IWA(N)
+      LOGICAL BWA(N)
+C     **********
+C
+C     SUBROUTINE M7SEQ
+C
+C     GIVEN THE SPARSITY PATTERN OF AN M BY N MATRIX A, THIS
+C     SUBROUTINE DETERMINES A CONSISTENT PARTITION OF THE
+C     COLUMNS OF A BY A SEQUENTIAL ALGORITHM.
+C
+C     A CONSISTENT PARTITION IS DEFINED IN TERMS OF THE LOOPLESS
+C     GRAPH G WITH VERTICES A(J), J = 1,2,...,N WHERE A(J) IS THE
+C     J-TH COLUMN OF A AND WITH EDGE (A(I),A(J)) IF AND ONLY IF
+C     COLUMNS I AND J HAVE A NON-ZERO IN THE SAME ROW POSITION.
+C
+C     A PARTITION OF THE COLUMNS OF A INTO GROUPS IS CONSISTENT
+C     IF THE COLUMNS IN ANY GROUP ARE NOT ADJACENT IN THE GRAPH G.
+C     IN GRAPH-THEORY TERMINOLOGY, A CONSISTENT PARTITION OF THE
+C     COLUMNS OF A CORRESPONDS TO A COLORING OF THE GRAPH G.
+C
+C     THE SUBROUTINE EXAMINES THE COLUMNS IN THE ORDER SPECIFIED
+C     BY THE ARRAY LIST, AND ASSIGNS THE CURRENT COLUMN TO THE
+C     GROUP WITH THE SMALLEST POSSIBLE NUMBER.
+C
+C     NOTE THAT THE VALUE OF M IS NOT NEEDED BY M7SEQ AND IS
+C     THEREFORE NOT PRESENT IN THE SUBROUTINE STATEMENT.
+C
+C     THE SUBROUTINE STATEMENT IS
+C
+C       SUBROUTINE M7SEQ(N,INDROW,JPNTR,INDCOL,IPNTR,LIST,NGRP,MAXGRP,
+C                      IWA,BWA)
+C
+C     WHERE
+C
+C       N IS A POSITIVE INTEGER INPUT VARIABLE SET TO THE NUMBER
+C         OF COLUMNS OF A.
+C
+C       INDROW IS AN INTEGER INPUT ARRAY WHICH CONTAINS THE ROW
+C         INDICES FOR THE NON-ZEROES IN THE MATRIX A.
+C
+C       JPNTR IS AN INTEGER INPUT ARRAY OF LENGTH N + 1 WHICH
+C         SPECIFIES THE LOCATIONS OF THE ROW INDICES IN INDROW.
+C         THE ROW INDICES FOR COLUMN J ARE
+C
+C               INDROW(K), K = JPNTR(J),...,JPNTR(J+1)-1.
+C
+C         NOTE THAT JPNTR(N+1)-1 IS THEN THE NUMBER OF NON-ZERO
+C         ELEMENTS OF THE MATRIX A.
+C
+C       INDCOL IS AN INTEGER INPUT ARRAY WHICH CONTAINS THE
+C         COLUMN INDICES FOR THE NON-ZEROES IN THE MATRIX A.
+C
+C       IPNTR IS AN INTEGER INPUT ARRAY OF LENGTH M + 1 WHICH
+C         SPECIFIES THE LOCATIONS OF THE COLUMN INDICES IN INDCOL.
+C         THE COLUMN INDICES FOR ROW I ARE
+C
+C               INDCOL(K), K = IPNTR(I),...,IPNTR(I+1)-1.
+C
+C         NOTE THAT IPNTR(M+1)-1 IS THEN THE NUMBER OF NON-ZERO
+C         ELEMENTS OF THE MATRIX A.
+C
+C       LIST IS AN INTEGER INPUT ARRAY OF LENGTH N WHICH SPECIFIES
+C         THE ORDER TO BE USED BY THE SEQUENTIAL ALGORITHM.
+C         THE J-TH COLUMN IN THIS ORDER IS LIST(J).
+C
+C       NGRP IS AN INTEGER OUTPUT ARRAY OF LENGTH N WHICH SPECIFIES
+C         THE PARTITION OF THE COLUMNS OF A. COLUMN JCOL BELONGS
+C         TO GROUP NGRP(JCOL).
+C
+C       MAXGRP IS AN INTEGER OUTPUT VARIABLE WHICH SPECIFIES THE
+C         NUMBER OF GROUPS IN THE PARTITION OF THE COLUMNS OF A.
+C
+C       IWA IS AN INTEGER WORK ARRAY OF LENGTH N.
+C
+C       BWA IS A LOGICAL WORK ARRAY OF LENGTH N.
+C
+C     ARGONNE NATIONAL LABORATORY. MINPACK PROJECT. JUNE 1982.
+C     THOMAS F. COLEMAN, BURTON S. GARBOW, JORGE J. MORE
+C
+C     **********
+      INTEGER DEG,IC,IP,IPL,IPU,IR,J,JCOL,JP,JPL,JPU,L,NUMGRP
+C
+C     INITIALIZATION BLOCK.
+C
+      MAXGRP = 0
+      DO 10 JP = 1, N
+         NGRP(JP) = N
+         BWA(JP) = .FALSE.
+   10    CONTINUE
+      BWA(N) = .TRUE.
+C
+C     BEGINNING OF ITERATION LOOP.
+C
+      DO 100 J = 1, N
+         JCOL = LIST(J)
+C
+C        FIND ALL COLUMNS ADJACENT TO COLUMN JCOL.
+C
+         DEG = 0
+C
+C        DETERMINE ALL POSITIONS (IR,JCOL) WHICH CORRESPOND
+C        TO NON-ZEROES IN THE MATRIX.
+C
+         JPL = JPNTR(JCOL)
+         JPU = JPNTR(JCOL+1) - 1
+         IF (JPU .LT. JPL) GO TO 50
+         DO 40 JP = JPL, JPU
+            IR = INDROW(JP)
+C
+C           FOR EACH ROW IR, DETERMINE ALL POSITIONS (IR,IC)
+C           WHICH CORRESPOND TO NON-ZEROES IN THE MATRIX.
+C
+            IPL = IPNTR(IR)
+            IPU = IPNTR(IR+1) - 1
+            DO 30 IP = IPL, IPU
+               IC = INDCOL(IP)
+               L = NGRP(IC)
+C
+C              ARRAY BWA MARKS THE GROUP NUMBERS OF THE
+C              COLUMNS WHICH ARE ADJACENT TO COLUMN JCOL.
+C              ARRAY IWA RECORDS THE MARKED GROUP NUMBERS.
+C
+               IF (BWA(L)) GO TO 20
+               BWA(L) = .TRUE.
+               DEG = DEG + 1
+               IWA(DEG) = L
+   20          CONTINUE
+   30          CONTINUE
+   40       CONTINUE
+   50    CONTINUE
+C
+C        ASSIGN THE SMALLEST UN-MARKED GROUP NUMBER TO JCOL.
+C
+         DO 60 JP = 1, N
+            NUMGRP = JP
+            IF (.NOT. BWA(JP)) GO TO 70
+   60       CONTINUE
+   70    CONTINUE
+         NGRP(JCOL) = NUMGRP
+         MAXGRP = MAX0(MAXGRP,NUMGRP)
+C
+C        UN-MARK THE GROUP NUMBERS.
+C
+         IF (DEG .LT. 1) GO TO 90
+         DO 80 JP = 1, DEG
+            L = IWA(JP)
+            BWA(L) = .FALSE.
+   80       CONTINUE
+   90    CONTINUE
+  100    CONTINUE
+C
+C        END OF ITERATION LOOP.
+C
+      RETURN
+C
+C     LAST CARD OF SUBROUTINE M7SEQ.
+C
+      END
+      SUBROUTINE DL7TSQ(N, A, L)
+C
+C  ***  SET A TO LOWER TRIANGLE OF (L**T) * L  ***
+C
+C  ***  L = N X N LOWER TRIANG. MATRIX STORED ROWWISE.  ***
+C  ***  A IS ALSO STORED ROWWISE AND MAY SHARE STORAGE WITH L.  ***
+C
+      INTEGER N
+      DOUBLE PRECISION A(*), L(*)
+C     DIMENSION A(N*(N+1)/2), L(N*(N+1)/2)
+C
+      INTEGER I, II, IIM1, I1, J, K, M
+      DOUBLE PRECISION LII, LJ
+C
+      II = 0
+      DO 50 I = 1, N
+         I1 = II + 1
+         II = II + I
+         M = 1
+         IF (I .EQ. 1) GO TO 30
+         IIM1 = II - 1
+         DO 20 J = I1, IIM1
+              LJ = L(J)
+              DO 10 K = I1, J
+                   A(M) = A(M) + LJ*L(K)
+                   M = M + 1
+ 10                CONTINUE
+ 20           CONTINUE
+ 30      LII = L(II)
+         DO 40 J = I1, II
+ 40           A(J) = LII * L(J)
+ 50      CONTINUE
+C
+      RETURN
+C  ***  LAST CARD OF DL7TSQ FOLLOWS  ***
+      END
+      DOUBLE PRECISION FUNCTION DRLDST(P, D, X, X0)
+C
+C  ***  COMPUTE AND RETURN RELATIVE DIFFERENCE BETWEEN X AND X0  ***
+C  ***  NL2SOL VERSION 2.2  ***
+C
+      INTEGER P
+      DOUBLE PRECISION D(P), X(P), X0(P)
+C
+      INTEGER I
+      DOUBLE PRECISION EMAX, T, XMAX, ZERO
+      PARAMETER (ZERO=0.D+0)
+C
+C  ***  BODY  ***
+C
+      EMAX = ZERO
+      XMAX = ZERO
+      DO 10 I = 1, P
+         T = DABS(D(I) * (X(I) - X0(I)))
+         IF (EMAX .LT. T) EMAX = T
+         T = D(I) * (DABS(X(I)) + DABS(X0(I)))
+         IF (XMAX .LT. T) XMAX = T
+ 10      CONTINUE
+      DRLDST = ZERO
+      IF (XMAX .GT. ZERO) DRLDST = EMAX / XMAX
+      RETURN
+C  ***  LAST CARD OF DRLDST FOLLOWS  ***
+      END
+      SUBROUTINE DRN2GB(B, D, DR, IV, LIV, LV, N, ND, N1, N2, P, R,
+     1                  RD, V, X)
+C
+C  ***  REVISED ITERATION DRIVER FOR NL2SOL WITH SIMPLE BOUNDS  ***
+C
+      INTEGER LIV, LV, N, ND, N1, N2, P
+      INTEGER IV(LIV)
+      DOUBLE PRECISION B(2,P), D(P), DR(ND,P), R(ND), RD(ND), V(LV),
+     1                 X(P)
+C
+C--------------------------  PARAMETER USAGE  --------------------------
+C
+C B........ BOUNDS ON X.
+C D........ SCALE VECTOR.
+C DR....... DERIVATIVES OF R AT X.
+C IV....... INTEGER VALUES ARRAY.
+C LIV...... LENGTH OF IV... LIV MUST BE AT LEAST 4*P + 82.
+C LV....... LENGTH OF V...  LV  MUST BE AT LEAST 105 + P*(2*P+20).
+C N........ TOTAL NUMBER OF RESIDUALS.
+C ND....... MAX. NO. OF RESIDUALS PASSED ON ONE CALL.
+C N1....... LOWEST  ROW INDEX FOR RESIDUALS SUPPLIED THIS TIME.
+C N2....... HIGHEST ROW INDEX FOR RESIDUALS SUPPLIED THIS TIME.
+C P........ NUMBER OF PARAMETERS (COMPONENTS OF X) BEING ESTIMATED.
+C R........ RESIDUALS.
+C V........ FLOATING-POINT VALUES ARRAY.
+C X........ PARAMETER VECTOR BEING ESTIMATED (INPUT = INITIAL GUESS,
+C             OUTPUT = BEST VALUE FOUND).
+C
+C  ***  DISCUSSION  ***
+C
+C     THIS ROUTINE CARRIES OUT ITERATIONS FOR SOLVING NONLINEAR
+C  LEAST SQUARES PROBLEMS.  IT IS SIMILAR TO  DRN2G, EXCEPT THAT
+C  THIS ROUTINE ENFORCES THE BOUNDS  B(1,I) .LE. X(I) .LE. B(2,I),
+C  I = 1(1)P.
+C
+C  ***  GENERAL  ***
+C
+C     CODED BY DAVID M. GAY.
+C
+C+++++++++++++++++++++++++++++  DECLARATIONS  ++++++++++++++++++++++++++
+C
+C  ***  EXTERNAL FUNCTIONS AND SUBROUTINES  ***
+C
+      DOUBLE PRECISION DD7TPR, DV2NRM
+      EXTERNAL DIVSET, DD7TPR,DD7UPD, DG7ITB,DITSUM,DL7VML, DQ7APL,
+     1        DQ7RAD, DR7TVM,DV7CPY, DV7SCP, DV2NRM
+C
+C DIVSET.... PROVIDES DEFAULT IV AND V INPUT COMPONENTS.
+C DD7TPR... COMPUTES INNER PRODUCT OF TWO VECTORS.
+C DD7UPD...  UPDATES SCALE VECTOR D.
+C DG7ITB... PERFORMS BASIC MINIMIZATION ALGORITHM.
+C DITSUM.... PRINTS ITERATION SUMMARY, INFO ABOUT INITIAL AND FINAL X.
+C DL7VML.... COMPUTES L * V, V = VECTOR, L = LOWER TRIANGULAR MATRIX.
+C DQ7APL... APPLIES QR TRANSFORMATIONS STORED BY DQ7RAD.
+C DQ7RAD.... ADDS A NEW BLOCK OF ROWS TO QR DECOMPOSITION.
+C DR7TVM... MULT. VECTOR BY TRANS. OF UPPER TRIANG. MATRIX FROM QR FACT.
+C DV7CPY.... COPIES ONE VECTOR TO ANOTHER.
+C DV7SCP... SETS ALL ELEMENTS OF A VECTOR TO A SCALAR.
+C DV2NRM... RETURNS THE 2-NORM OF A VECTOR.
+C
+C
+C  ***  LOCAL VARIABLES  ***
+C
+      INTEGER G1, GI, I, IV1, IVMODE, JTOL1, L, LH, NN, QTR1,
+     1        RD1, RMAT1, YI, Y1
+      DOUBLE PRECISION T
+C
+      DOUBLE PRECISION HALF, ZERO
+C
+C  ***  SUBSCRIPTS FOR IV AND V  ***
+C
+      INTEGER DINIT, DTYPE, DTINIT, D0INIT, F, G, JCN, JTOL, MODE,
+     1        NEXTV, NF0, NF00, NF1, NFCALL, NFCOV, NFGCAL, QTR, RDREQ,
+     1        REGD, RESTOR, RLIMIT, RMAT, TOOBIG, VNEED
+C
+C  ***  IV SUBSCRIPT VALUES  ***
+C
+      PARAMETER (DTYPE=16, G=28, JCN=66, JTOL=59, MODE=35, NEXTV=47,
+     1           NF0=68, NF00=81, NF1=69, NFCALL=6, NFCOV=52, NFGCAL=7,
+     2           QTR=77, RDREQ=57, RESTOR=9, REGD=67, RMAT=78, TOOBIG=2,
+     3           VNEED=4)
+C
+C  ***  V SUBSCRIPT VALUES  ***
+C
+      PARAMETER (DINIT=38, DTINIT=39, D0INIT=40, F=10, RLIMIT=46)
+      PARAMETER (HALF=0.5D+0, ZERO=0.D+0)
+C
+C+++++++++++++++++++++++++++++++  BODY  ++++++++++++++++++++++++++++++++
+C
+      LH = P * (P+1) / 2
+      IF (IV(1) .EQ. 0) CALL DIVSET(1, IV, LIV, LV, V)
+      IV1 = IV(1)
+      IF (IV1 .GT. 2) GO TO 10
+         NN = N2 - N1 + 1
+         IV(RESTOR) = 0
+         I = IV1 + 4
+         IF (IV(TOOBIG) .EQ. 0) GO TO (150, 130, 150, 120, 120, 150), I
+         IF (I .NE. 5) IV(1) = 2
+         GO TO 40
+C
+C  ***  FRESH START OR RESTART -- CHECK INPUT INTEGERS  ***
+C
+ 10   IF (ND .LE. 0) GO TO 220
+      IF (P .LE. 0) GO TO 220
+      IF (N .LE. 0) GO TO 220
+      IF (IV1 .EQ. 14) GO TO 30
+      IF (IV1 .GT. 16) GO TO 270
+      IF (IV1 .LT. 12) GO TO 40
+      IF (IV1 .EQ. 12) IV(1) = 13
+      IF (IV(1) .NE. 13) GO TO 20
+      IV(VNEED) = IV(VNEED) + P*(P+15)/2
+ 20   CALL DG7ITB(B, D, X, IV, LIV, LV, P, P, V, X, X)
+      IF (IV(1) .NE. 14) GO TO 999
+C
+C  ***  STORAGE ALLOCATION  ***
+C
+      IV(G) = IV(NEXTV)
+      IV(JCN) = IV(G) + 2*P
+      IV(RMAT) = IV(JCN) + P
+      IV(QTR) = IV(RMAT) + LH
+      IV(JTOL) = IV(QTR) + 2*P
+      IV(NEXTV) = IV(JTOL) + 2*P
+C  ***  TURN OFF COVARIANCE COMPUTATION  ***
+      IV(RDREQ) = 0
+      IF (IV1 .EQ. 13) GO TO 999
+C
+ 30   JTOL1 = IV(JTOL)
+      IF (V(DINIT) .GE. ZERO) CALL DV7SCP(P, D, V(DINIT))
+      IF (V(DTINIT) .GT. ZERO) CALL DV7SCP(P, V(JTOL1), V(DTINIT))
+      I = JTOL1 + P
+      IF (V(D0INIT) .GT. ZERO) CALL DV7SCP(P, V(I), V(D0INIT))
+      IV(NF0) = 0
+      IV(NF1) = 0
+      IF (ND .GE. N) GO TO 40
+C
+C  ***  SPECIAL CASE HANDLING OF FIRST FUNCTION AND GRADIENT EVALUATION
+C  ***  -- ASK FOR BOTH RESIDUAL AND JACOBIAN AT ONCE
+C
+      G1 = IV(G)
+      Y1 = G1 + P
+      CALL DG7ITB(B, D, V(G1), IV, LIV, LV, P, P, V, X, V(Y1))
+      IF (IV(1) .NE. 1) GO TO 260
+      V(F) = ZERO
+      CALL DV7SCP(P, V(G1), ZERO)
+      IV(1) = -1
+      QTR1 = IV(QTR)
+      CALL DV7SCP(P, V(QTR1), ZERO)
+      IV(REGD) = 0
+      RMAT1 = IV(RMAT)
+      GO TO 100
+C
+ 40   G1 = IV(G)
+      Y1 = G1 + P
+      CALL DG7ITB(B, D, V(G1), IV, LIV, LV, P, P, V, X, V(Y1))
+      IF (IV(1) .EQ. 2) GO TO 60
+      IF (IV(1) .GT. 2) GO TO 260
+C
+      V(F) = ZERO
+      IF (IV(NF1) .EQ. 0) GO TO 240
+      IF (IV(RESTOR) .NE. 2) GO TO 240
+      IV(NF0) = IV(NF1)
+      CALL DV7CPY(N, RD, R)
+      IV(REGD) = 0
+      GO TO 240
+C
+ 60   CALL DV7SCP(P, V(G1), ZERO)
+      IF (IV(MODE) .GT. 0) GO TO 230
+      RMAT1 = IV(RMAT)
+      QTR1 = IV(QTR)
+      RD1 = QTR1 + P
+      CALL DV7SCP(P, V(QTR1), ZERO)
+      IV(REGD) = 0
+      IF (ND .LT. N) GO TO 90
+      IF (N1 .NE. 1) GO TO 90
+      IF (IV(MODE) .LT. 0) GO TO 100
+      IF (IV(NF1) .EQ. IV(NFGCAL)) GO TO 70
+         IF (IV(NF0) .NE. IV(NFGCAL)) GO TO 90
+            CALL DV7CPY(N, R, RD)
+            GO TO 80
+ 70   CALL DV7CPY(N, RD, R)
+ 80   CALL DQ7APL(ND, N, P, DR, RD, 0)
+      CALL DR7TVM(ND, MIN0(N,P), V(Y1), V(RD1), DR, RD)
+      IV(REGD) = 0
+      GO TO 110
+C
+ 90   IV(1) = -2
+      IF (IV(MODE) .LT. 0) IV(1) = -3
+ 100  CALL DV7SCP(P, V(Y1), ZERO)
+ 110  CALL DV7SCP(LH, V(RMAT1), ZERO)
+      GO TO 240
+C
+C  ***  COMPUTE F(X)  ***
+C
+ 120  T = DV2NRM(NN, R)
+      IF (T .GT. V(RLIMIT)) GO TO 210
+      V(F) = V(F)  +  HALF * T**2
+      IF (N2 .LT. N) GO TO 250
+      IF (N1 .EQ. 1) IV(NF1) = IV(NFCALL)
+      GO TO 40
+C
+C  ***  COMPUTE Y  ***
+C
+ 130  Y1 = IV(G) + P
+      YI = Y1
+      DO 140 L = 1, P
+         V(YI) = V(YI) + DD7TPR(NN, DR(1,L), R)
+         YI = YI + 1
+ 140     CONTINUE
+      IF (N2 .LT. N) GO TO 250
+         IV(1) = 2
+         IF (N1 .GT. 1) IV(1) = -3
+         GO TO 240
+C
+C  ***  COMPUTE GRADIENT INFORMATION  ***
+C
+ 150  G1 = IV(G)
+      IVMODE = IV(MODE)
+      IF (IVMODE .LT. 0) GO TO 170
+      IF (IVMODE .EQ. 0) GO TO 180
+      IV(1) = 2
+C
+C  ***  COMPUTE GRADIENT ONLY (FOR USE IN COVARIANCE COMPUTATION)  ***
+C
+      GI = G1
+      DO 160 L = 1, P
+         V(GI) = V(GI) + DD7TPR(NN, R, DR(1,L))
+         GI = GI + 1
+ 160     CONTINUE
+      GO TO 200
+C
+C  *** COMPUTE INITIAL FUNCTION VALUE WHEN ND .LT. N ***
+C
+ 170  IF (N .LE. ND) GO TO 180
+         T = DV2NRM(NN, R)
+         IF (T .GT. V(RLIMIT)) GO TO 210
+         V(F) = V(F)  +  HALF * T**2
+C
+C  ***  UPDATE D IF DESIRED  ***
+C
+ 180  IF (IV(DTYPE) .GT. 0)
+     1      CALL DD7UPD(D, DR, IV, LIV, LV, N, ND, NN, N2, P, V)
+C
+C  ***  COMPUTE RMAT AND QTR  ***
+C
+      QTR1 = IV(QTR)
+      RMAT1 = IV(RMAT)
+      CALL DQ7RAD(NN, ND, P, V(QTR1), .TRUE., V(RMAT1), DR, R)
+      IV(NF1) = 0
+      IF (N1 .GT. 1) GO TO 200
+      IF (N2 .LT. N) GO TO 250
+C
+C  ***  SAVE DIAGONAL OF R FOR COMPUTING Y LATER  ***
+C
+      RD1 = QTR1 + P
+      L = RMAT1 - 1
+      DO 190 I = 1, P
+         L = L + I
+         V(RD1) = V(L)
+         RD1 = RD1 + 1
+ 190     CONTINUE
+C
+ 200  IF (N2 .LT. N) GO TO 250
+      IF (IVMODE .GT. 0) GO TO 40
+      IV(NF00) = IV(NFGCAL)
+C
+C  ***  COMPUTE G FROM RMAT AND QTR  ***
+C
+      CALL DL7VML(P, V(G1), V(RMAT1), V(QTR1))
+      IV(1) = 2
+      IF (IVMODE .EQ. 0) GO TO 40
+      IF (N .LE. ND) GO TO 40
+C
+C  ***  FINISH SPECIAL CASE HANDLING OF FIRST FUNCTION AND GRADIENT
+C
+      Y1 = G1 + P
+      IV(1) = 1
+      CALL DG7ITB(B, D, V(G1), IV, LIV, LV, P, P, V, X, V(Y1))
+      IF (IV(1) .NE. 2) GO TO 260
+      GO TO 40
+C
+C  ***  MISC. DETAILS  ***
+C
+C     ***  X IS OUT OF RANGE (OVERSIZE STEP)  ***
+C
+ 210  IV(TOOBIG) = 1
+      GO TO 40
+C
+C     ***  BAD N, ND, OR P  ***
+C
+ 220  IV(1) = 66
+      GO TO 270
+C
+C  ***  RECORD EXTRA EVALUATIONS FOR FINITE-DIFFERENCE HESSIAN  ***
+C
+ 230  IV(NFCOV) = IV(NFCOV) + 1
+      IV(NFCALL) = IV(NFCALL) + 1
+      IV(NFGCAL) = IV(NFCALL)
+      IV(1) = -1
+C
+C  ***  RETURN FOR MORE FUNCTION OR GRADIENT INFORMATION  ***
+C
+ 240  N2 = 0
+ 250  N1 = N2 + 1
+      N2 = N2 + ND
+      IF (N2 .GT. N) N2 = N
+      GO TO 999
+C
+C  ***  PRINT SUMMARY OF FINAL ITERATION AND OTHER REQUESTED ITEMS  ***
+C
+ 260  G1 = IV(G)
+ 270  CALL DITSUM(D, V(G1), IV, LIV, LV, P, V, X)
+C
+ 999  RETURN
+C  ***  LAST CARD OF DRN2GB FOLLOWS  ***
+      END
+        SUBROUTINE DD7DGB(B, D, DIG, DST, G, IPIV, KA, L, LV, P, PC,
+     1                    NWTST, STEP, TD, TG, V, W, X0)
+C
+C  ***  COMPUTE DOUBLE-DOGLEG STEP, SUBJECT TO SIMPLE BOUNDS ON X  ***
+C
+      INTEGER LV, KA, P, PC
+      INTEGER IPIV(P)
+      DOUBLE PRECISION B(2,P), D(P), DIG(P), DST(P), G(P), L(*),
+     1                 NWTST(P), STEP(P), TD(P), TG(P), V(LV), W(P),
+     2                 X0(P)
+C
+C     DIMENSION L(P*(P+1)/2)
+C
+      DOUBLE PRECISION DD7TPR, DR7MDC, DV2NRM
+      EXTERNAL DD7DOG, DD7TPR, I7SHFT, DL7ITV, DL7IVM, DL7TVM,DL7VML,
+     1         DQ7RSH, DR7MDC, DV2NRM,DV2AXY,DV7CPY, DV7IPR, DV7SCP,
+     2         DV7SHF, DV7VMP
+C
+C  ***  LOCAL VARIABLES  ***
+C
+      INTEGER I, J, K, P1, P1M1
+      DOUBLE PRECISION DNWTST, GHINVG, GNORM, GNORM0, NRED, PRED, RAD,
+     1                 T, T1, T2, TI, X0I, XI
+      DOUBLE PRECISION HALF, MEPS2, ONE, TWO, ZERO
+C
+C  ***  V SUBSCRIPTS  ***
+C
+      INTEGER DGNORM, DST0, DSTNRM, GRDFAC, GTHG, GTSTEP, NREDUC,
+     1        NWTFAC, PREDUC, RADIUS, STPPAR
+C
+      PARAMETER (DGNORM=1, DST0=3, DSTNRM=2, GRDFAC=45, GTHG=44,
+     1           GTSTEP=4, NREDUC=6, NWTFAC=46, PREDUC=7, RADIUS=8,
+     2           STPPAR=5)
+      PARAMETER (HALF=0.5D+0, ONE=1.D+0, TWO=2.D+0, ZERO=0.D+0)
+      SAVE MEPS2
+      DATA MEPS2/0.D+0/
+C
+C+++++++++++++++++++++++++++++++  BODY  ++++++++++++++++++++++++++++++++
+C
+      IF (MEPS2 .LE. ZERO) MEPS2 = TWO * DR7MDC(3)
+      GNORM0 = V(DGNORM)
+      V(DSTNRM) = ZERO
+      IF (KA .LT. 0) GO TO 10
+         DNWTST = V(DST0)
+         NRED = V(NREDUC)
+ 10   PRED = ZERO
+      V(STPPAR) = ZERO
+      RAD = V(RADIUS)
+      IF (PC .GT. 0) GO TO 20
+         DNWTST = ZERO
+         CALL DV7SCP(P, STEP, ZERO)
+         GO TO 140
+C
+ 20   P1 = PC
+      CALL DV7CPY(P, TD, D)
+      CALL DV7IPR(P, IPIV, TD)
+      CALL DV7SCP(PC, DST, ZERO)
+      CALL DV7CPY(P, TG, G)
+      CALL DV7IPR(P, IPIV, TG)
+C
+ 30   CALL DL7IVM(P1, NWTST, L, TG)
+      GHINVG = DD7TPR(P1, NWTST, NWTST)
+      V(NREDUC) = HALF * GHINVG
+      CALL DL7ITV(P1, NWTST, L, NWTST)
+      CALL DV7VMP(P1, STEP, NWTST, TD, 1)
+      V(DST0) = DV2NRM(PC, STEP)
+      IF (KA .GE. 0) GO TO 40
+         KA = 0
+         DNWTST = V(DST0)
+         NRED = V(NREDUC)
+ 40   V(RADIUS) = RAD - V(DSTNRM)
+      IF (V(RADIUS) .LE. ZERO) GO TO 100
+      CALL DV7VMP(P1, DIG, TG, TD, -1)
+      GNORM = DV2NRM(P1, DIG)
+      IF (GNORM .LE. ZERO) GO TO 100
+      V(DGNORM) = GNORM
+      CALL DV7VMP(P1, DIG, DIG, TD, -1)
+      CALL DL7TVM(P1, W, L, DIG)
+      V(GTHG) = DV2NRM(P1, W)
+      KA = KA + 1
+      CALL DD7DOG(DIG, LV, P1, NWTST, STEP, V)
+C
+C     ***  FIND T SUCH THAT X - T*STEP IS STILL FEASIBLE.
+C
+      T = ONE
+      K = 0
+      DO 70 I = 1, P1
+         J = IPIV(I)
+         X0I = X0(J) + DST(I)/TD(I)
+         XI = X0I + STEP(I)
+         IF (XI .LT. B(1,J)) GO TO 50
+         IF (XI .LE. B(2,J)) GO TO 70
+              TI = (B(2,J) - X0I) / STEP(I)
+              J = I
+              GO TO 60
+ 50      TI = (B(1,J) - X0I) / STEP(I)
+         J = -I
+ 60      IF (T .LE. TI) GO TO 70
+              K = J
+              T = TI
+ 70      CONTINUE
+C
+C  ***  UPDATE DST, TG, AND PRED  ***
+C
+      CALL DV7VMP(P1, STEP, STEP, TD, 1)
+      CALL DV2AXY(P1, DST, T, STEP, DST)
+      V(DSTNRM) = DV2NRM(PC, DST)
+      T1 = T * V(GRDFAC)
+      T2 = T * V(NWTFAC)
+      PRED = PRED - T1*GNORM * ((T2 + ONE)*GNORM)
+     1                 - T2 * (ONE + HALF*T2)*GHINVG
+     2                  - HALF * (V(GTHG)*T1)**2
+      IF (K .EQ. 0) GO TO 100
+      CALL DL7VML(P1, W, L, W)
+      T2 = ONE - T2
+      DO 80 I = 1, P1
+ 80      TG(I) = T2*TG(I) - T1*W(I)
+C
+C     ***  PERMUTE L, ETC. IF NECESSARY  ***
+C
+      P1M1 = P1 - 1
+      J = IABS(K)
+      IF (J .EQ. P1) GO TO 90
+         CALL DQ7RSH(J, P1, .FALSE., TG, L, W)
+         CALL I7SHFT(P1, J, IPIV)
+         CALL DV7SHF(P1, J, TG)
+         CALL DV7SHF(P1, J, TD)
+         CALL DV7SHF(P1, J, DST)
+ 90   IF (K .LT. 0) IPIV(P1) = -IPIV(P1)
+      P1 = P1M1
+      IF (P1 .GT. 0) GO TO 30
+C
+C     ***  UNSCALE STEP, UPDATE X AND DIHDI  ***
+C
+ 100  CALL DV7SCP(P, STEP, ZERO)
+      DO 110 I = 1, PC
+         J = IABS(IPIV(I))
+         STEP(J) = DST(I) / TD(I)
+ 110     CONTINUE
+C
+C  ***  FUDGE STEP TO ENSURE THAT IT FORCES APPROPRIATE COMPONENTS
+C  ***  TO THEIR BOUNDS  ***
+C
+      IF (P1 .GE. PC) GO TO 140
+      CALL DV2AXY(P, TD, ONE, STEP, X0)
+      K = P1 + 1
+      DO 130 I = K, PC
+         J = IPIV(I)
+         T = MEPS2
+         IF (J .GT. 0) GO TO 120
+            T = -T
+            J = -J
+            IPIV(I) = J
+ 120     T = T * DMAX1(DABS(TD(J)), DABS(X0(J)))
+         STEP(J) = STEP(J) + T
+ 130     CONTINUE
+C
+ 140  V(DGNORM) = GNORM0
+      V(NREDUC) = NRED
+      V(PREDUC) = PRED
+      V(RADIUS) = RAD
+      V(DST0) = DNWTST
+      V(GTSTEP) = DD7TPR(P, STEP, G)
+C
+      RETURN
+C  ***  LAST LINE OF DD7DGB FOLLOWS  ***
+      END
+      SUBROUTINE DQ7RFH(IERR, IPIVOT, N, NN, NOPIVK, P, Q, R, RLEN, W)
+C
+C  ***  COMPUTE QR FACTORIZATION VIA HOUSEHOLDER TRANSFORMATIONS
+C  ***  WITH COLUMN PIVOTING  ***
+C
+C  ***  PARAMETER DECLARATIONS  ***
+C
+      INTEGER IERR, N, NN, NOPIVK, P, RLEN
+      INTEGER IPIVOT(P)
+      DOUBLE PRECISION Q(NN,P), R(RLEN), W(P)
+C     DIMENSION R(P*(P+1)/2)
+C
+C----------------------------  DESCRIPTION  ----------------------------
+C
+C    THIS ROUTINE COMPUTES A QR FACTORIZATION (VIA HOUSEHOLDER TRANS-
+C FORMATIONS) OF THE MATRIX  A  THAT ON INPUT IS STORED IN Q.
+C IF  NOPIVK  ALLOWS IT, THIS ROUTINE DOES COLUMN PIVOTING -- IF
+C K .GT. NOPIVK,  THEN ORIGINAL COLUMN  K  IS ELIGIBLE FOR PIVOTING.
+C THE  Q  AND  R  RETURNED ARE SUCH THAT COLUMN  I  OF  Q*R  EQUALS
+C COLUMN  IPIVOT(I)  OF THE ORIGINAL MATRIX  A.  THE UPPER TRIANGULAR
+C MATRIX  R  IS STORED COMPACTLY BY COLUMNS, I.E., THE OUTPUT VECTOR  R
+C CONTAINS  R(1,1), R(1,2), R(2,2), R(1,3), R(2,3), ..., R(P,P) (IN
+C THAT ORDER).  IF ALL GOES WELL, THEN THIS ROUTINE SETS  IERR = 0.
+C BUT IF (PERMUTED) COLUMN  K  OF  A  IS LINEARLY DEPENDENT ON
+C (PERMUTED) COLUMNS 1,2,...,K-1, THEN  IERR  IS SET TO  K AND THE R
+C MATRIX RETURNED HAS  R(I,J) = 0  FOR  I .GE. K  AND  J .GE. K.
+C    THE ORIGINAL MATRIX  A  IS AN N BY P MATRIX.  NN  IS THE LEAD
+C DIMENSION OF THE ARRAY  Q  AND MUST SATISFY  NN .GE. N.  NO
+C PARAMETER CHECKING IS DONE.
+C    PIVOTING IS DONE AS THOUGH ALL COLUMNS OF Q WERE FIRST
+C SCALED TO HAVE THE SAME NORM.  IF COLUMN K IS ELIGIBLE FOR
+C PIVOTING AND ITS (SCALED) NORM**2 LOSS IS MORE THAN THE
+C MINIMUM SUCH LOSS (OVER COLUMNS K THRU P), THEN COLUMN K IS
+C SWAPPED WITH THE COLUMN OF LEAST NORM**2 LOSS.
+C
+C        CODED BY DAVID M. GAY (FALL 1979, SPRING 1984).
+C
+C--------------------------  LOCAL VARIABLES  --------------------------
+C
+      INTEGER I, II, J, K, KK, KM1, KP1, NK1
+      DOUBLE PRECISION AK, QKK, S, SINGTL, T, T1, WK
+      DOUBLE PRECISION DD7TPR, DR7MDC, DV2NRM
+      EXTERNAL DD7TPR, DR7MDC,DV2AXY, DV7SCL, DV7SCP,DV7SWP, DV2NRM
+C/+
+      DOUBLE PRECISION DSQRT
+C/
+      DOUBLE PRECISION BIG, BIGRT, MEPS10, ONE, TEN, TINY, TINYRT,
+     1                 WTOL, ZERO
+      PARAMETER (ONE=1.0D+0, TEN=1.D+1, WTOL=0.75D+0, ZERO=0.0D+0)
+      SAVE BIGRT, MEPS10, TINY, TINYRT
+      DATA BIGRT/0.0D+0/, MEPS10/0.0D+0/, TINY/0.D+0/, TINYRT/0.D+0/
+C
+C+++++++++++++++++++++++++++++++  BODY  ++++++++++++++++++++++++++++++++
+C
+      IERR = 0
+      IF (MEPS10 .GT. ZERO) GO TO 10
+          BIGRT = DR7MDC(5)
+          MEPS10 = TEN * DR7MDC(3)
+          TINYRT = DR7MDC(2)
+          TINY = DR7MDC(1)
+          BIG = DR7MDC(6)
+          IF (TINY*BIG .LT. ONE) TINY = ONE / BIG
+ 10   SINGTL = DBLE(MAX0(N,P)) * MEPS10
+C
+C  ***  INITIALIZE W, IPIVOT, AND DIAG(R)  ***
+C
+      J = 0
+      DO 40 I = 1, P
+         IPIVOT(I) = I
+         T = DV2NRM(N, Q(1,I))
+         IF (T .GT. ZERO) GO TO 20
+              W(I) = ONE
+              GO TO 30
+ 20      W(I) = ZERO
+ 30      J = J + I
+         R(J) = T
+ 40      CONTINUE
+C
+C  ***  MAIN LOOP  ***
+C
+      KK = 0
+      NK1 = N + 1
+      DO 130 K = 1, P
+         IF (NK1 .LE. 1) GO TO 999
+         NK1 = NK1 - 1
+         KK = KK + K
+         KP1 = K + 1
+         IF (K .LE. NOPIVK) GO TO 60
+         IF (K .GE. P) GO TO 60
+C
+C        ***  FIND COLUMN WITH MINIMUM WEIGHT LOSS  ***
+C
+              T = W(K)
+              IF (T .LE. ZERO) GO TO 60
+              J = K
+              DO 50 I = KP1, P
+                   IF (W(I) .GE. T) GO TO 50
+                        T = W(I)
+                        J = I
+ 50                CONTINUE
+              IF (J .EQ. K) GO TO 60
+C
+C             ***  INTERCHANGE COLUMNS K AND J  ***
+C
+                   I = IPIVOT(K)
+                   IPIVOT(K) = IPIVOT(J)
+                   IPIVOT(J) = I
+                   W(J) = W(K)
+                   W(K) = T
+                   I = J*(J+1)/2
+                   T1 = R(I)
+                   R(I) = R(KK)
+                   R(KK) = T1
+                   CALL DV7SWP(N, Q(1,K), Q(1,J))
+                   IF (K .LE. 1) GO TO 60
+                        I = I - J + 1
+                        J = KK - K + 1
+                        CALL DV7SWP(K-1, R(I), R(J))
+C
+C        ***  COLUMN K OF Q SHOULD BE NEARLY ORTHOGONAL TO THE PREVIOUS
+C        ***  COLUMNS.  NORMALIZE IT, TEST FOR SINGULARITY, AND DECIDE
+C        ***  WHETHER TO REORTHOGONALIZE IT.
+C
+ 60      AK = R(KK)
+         IF (AK .LE. ZERO) GO TO 140
+         WK = W(K)
+C
+C        *** SET T TO THE NORM OF (Q(K,K),...,Q(N,K))
+C        *** AND CHECK FOR SINGULARITY.
+C
+         IF (WK .LT. WTOL) GO TO 70
+            T = DV2NRM(NK1, Q(K,K))
+            IF (T / AK .LE. SINGTL) GO TO 140
+            GO TO 80
+ 70      T = DSQRT(ONE - WK)
+         IF (T .LE. SINGTL) GO TO 140
+         T = T * AK
+C
+C        *** DETERMINE HOUSEHOLDER TRANSFORMATION ***
+C
+ 80      QKK = Q(K,K)
+         IF (T .LE. TINYRT) GO TO 90
+         IF (T .GE. BIGRT) GO TO 90
+            IF (QKK .LT. ZERO) T = -T
+            QKK = QKK + T
+            S = DSQRT(T * QKK)
+            GO TO 110
+ 90       S = DSQRT(T)
+          IF (QKK .LT. ZERO) GO TO 100
+             QKK = QKK + T
+             S = S * DSQRT(QKK)
+             GO TO 110
+ 100      T = -T
+          QKK = QKK + T
+          S = S * DSQRT(-QKK)
+ 110      Q(K,K) = QKK
+C
+C         ***  SCALE (Q(K,K),...,Q(N,K)) TO HAVE NORM SQRT(2)  ***
+C
+          IF (S .LE. TINY) GO TO 140
+          CALL DV7SCL(NK1, Q(K,K), ONE/S, Q(K,K))
+C
+          R(KK) = -T
+C
+C        ***  COMPUTE R(K,I) FOR I = K+1,...,P AND UPDATE Q  ***
+C
+         IF (K .GE. P) GO TO 999
+         J = KK + K
+         II = KK
+         DO 120 I = KP1, P
+              II = II + I
+              CALL DV2AXY(NK1, Q(K,I), -DD7TPR(NK1,Q(K,K),Q(K,I)),
+     1                   Q(K,K), Q(K,I))
+              T = Q(K,I)
+              R(J) = T
+              J = J + I
+              T1 = R(II)
+              IF (T1 .GT. ZERO)  W(I) = W(I) + (T/T1)**2
+ 120          CONTINUE
+ 130     CONTINUE
+C
+C  ***  SINGULAR Q  ***
+C
+ 140  IERR = K
+      KM1 = K - 1
+      J = KK
+      DO 150 I = K, P
+         CALL DV7SCP(I-KM1, R(J), ZERO)
+         J = J + I
+ 150     CONTINUE
+C
+ 999  RETURN
+C  ***  LAST CARD OF DQ7RFH FOLLOWS  ***
+      END
+      SUBROUTINE DF7DHB(B, D, G, IRT, IV, LIV, LV, P, V, X)
+C
+C  ***  COMPUTE FINITE-DIFFERENCE HESSIAN, STORE IT IN V STARTING
+C  ***  AT V(IV(FDH)) = V(-IV(H)).  HONOR SIMPLE BOUNDS IN B.
+C
+C  ***  IF IV(COVREQ) .GE. 0 THEN DF7DHB USES GRADIENT DIFFERENCES,
+C  ***  OTHERWISE FUNCTION DIFFERENCES.  STORAGE IN V IS AS IN DG7LIT.
+C
+C IRT VALUES...
+C     1 = COMPUTE FUNCTION VALUE, I.E., V(F).
+C     2 = COMPUTE G.
+C     3 = DONE.
+C
+C
+C  ***  PARAMETER DECLARATIONS  ***
+C
+      INTEGER IRT, LIV, LV, P
+      INTEGER IV(LIV)
+      DOUBLE PRECISION B(2,P), D(P), G(P), V(LV), X(P)
+C
+C  ***  LOCAL VARIABLES  ***
+C
+      LOGICAL OFFSID
+      INTEGER GSAVE1, HES, HMI, HPI, HPM, I, K, KIND, L, M, MM1, MM1O2,
+     1        NEWM1, PP1O2, STPI, STPM, STP0
+      DOUBLE PRECISION DEL, DEL0, T, XM, XM1
+      DOUBLE PRECISION HALF, HLIM, ONE, TWO, ZERO
+C
+C  ***  EXTERNAL SUBROUTINES  ***
+C
+      EXTERNAL DV7CPY, DV7SCP
+C
+C DV7CPY.... COPY ONE VECTOR TO ANOTHER.
+C DV7SCP... COPY SCALAR TO ALL COMPONENTS OF A VECTOR.
+C
+C  ***  SUBSCRIPTS FOR IV AND V  ***
+C
+      INTEGER COVREQ, DELTA, DELTA0, DLTFDC, F, FDH, FX, H, KAGQT, MODE,
+     1        NFGCAL, SAVEI, SWITCH, TOOBIG, W, XMSAVE
+C
+      PARAMETER (HALF=0.5D+0, HLIM=0.1D+0, ONE=1.D+0, TWO=2.D+0,
+     1           ZERO=0.D+0)
+C
+      PARAMETER (COVREQ=15, DELTA=52, DELTA0=44, DLTFDC=42, F=10,
+     1           FDH=74, FX=53, H=56, KAGQT=33, MODE=35, NFGCAL=7,
+     2           SAVEI=63, SWITCH=12, TOOBIG=2, W=65, XMSAVE=51)
+C
+C+++++++++++++++++++++++++++++++  BODY  ++++++++++++++++++++++++++++++++
+C
+      IRT = 4
+      KIND = IV(COVREQ)
+      M = IV(MODE)
+      IF (M .GT. 0) GO TO 10
+         HES = IABS(IV(H))
+         IV(H) = -HES
+         IV(FDH) = 0
+         IV(KAGQT) = -1
+         V(FX) = V(F)
+C        *** SUPPLY ZEROS IN CASE B(1,I) = B(2,I) FOR SOME I ***
+         CALL DV7SCP(P*(P+1)/2, V(HES), ZERO)
+ 10   IF (M .GT. P) GO TO 999
+      IF (KIND .LT. 0) GO TO 120
+C
+C  ***  COMPUTE FINITE-DIFFERENCE HESSIAN USING BOTH FUNCTION AND
+C  ***  GRADIENT VALUES.
+C
+      GSAVE1 = IV(W) + P
+      IF (M .GT. 0) GO TO 20
+C        ***  FIRST CALL ON DF7DHB.  SET GSAVE = G, TAKE FIRST STEP  ***
+         CALL DV7CPY(P, V(GSAVE1), G)
+         IV(SWITCH) = IV(NFGCAL)
+         GO TO 80
+C
+ 20   DEL = V(DELTA)
+      X(M) = V(XMSAVE)
+      IF (IV(TOOBIG) .EQ. 0) GO TO 30
+C
+C     ***  HANDLE OVERSIZE V(DELTA)  ***
+C
+         DEL0 = V(DELTA0) * DMAX1(ONE/D(M), DABS(X(M)))
+         DEL = HALF * DEL
+         IF (DABS(DEL/DEL0) .LE. HLIM) GO TO 140
+C
+ 30   HES = -IV(H)
+C
+C  ***  SET  G = (G - GSAVE)/DEL  ***
+C
+      DEL = ONE / DEL
+      DO 40 I = 1, P
+         G(I) = DEL * (G(I) - V(GSAVE1))
+         GSAVE1 = GSAVE1 + 1
+ 40      CONTINUE
+C
+C  ***  ADD G AS NEW COL. TO FINITE-DIFF. HESSIAN MATRIX  ***
+C
+      K = HES + M*(M-1)/2
+      L = K + M - 2
+      IF (M .EQ. 1) GO TO 60
+C
+C  ***  SET  H(I,M) = 0.5 * (H(I,M) + G(I))  FOR I = 1 TO M-1  ***
+C
+      MM1 = M - 1
+      DO 50 I = 1, MM1
+         IF (B(1,I) .LT. B(2,I)) V(K) = HALF * (V(K) + G(I))
+         K = K + 1
+ 50      CONTINUE
+C
+C  ***  ADD  H(I,M) = G(I)  FOR I = M TO P  ***
+C
+ 60   L = L + 1
+      DO 70 I = M, P
+         IF (B(1,I) .LT. B(2,I)) V(L) = G(I)
+         L = L + I
+ 70      CONTINUE
+C
+ 80   M = M + 1
+      IV(MODE) = M
+      IF (M .GT. P) GO TO 340
+      IF (B(1,M) .GE. B(2,M)) GO TO 80
+C
+C  ***  CHOOSE NEXT FINITE-DIFFERENCE STEP, RETURN TO GET G THERE  ***
+C
+      DEL = V(DELTA0) * DMAX1(ONE/D(M), DABS(X(M)))
+      XM = X(M)
+      IF (XM .LT. ZERO) GO TO 90
+         XM1 = XM + DEL
+         IF (XM1 .LE. B(2,M)) GO TO 110
+           XM1 = XM - DEL
+           IF (XM1 .GE. B(1,M)) GO TO 100
+           GO TO 280
+ 90    XM1 = XM - DEL
+       IF (XM1 .GE. B(1,M)) GO TO 100
+       XM1 = XM + DEL
+       IF (XM1 .LE. B(2,M)) GO TO 110
+       GO TO 280
+C
+ 100  DEL = -DEL
+ 110  V(XMSAVE) = XM
+      X(M) = XM1
+      V(DELTA) = DEL
+      IRT = 2
+      GO TO 999
+C
+C  ***  COMPUTE FINITE-DIFFERENCE HESSIAN USING FUNCTION VALUES ONLY.
+C
+ 120  STP0 = IV(W) + P - 1
+      MM1 = M - 1
+      MM1O2 = M*MM1/2
+      HES = -IV(H)
+      IF (M .GT. 0) GO TO 130
+C        ***  FIRST CALL ON DF7DHB.  ***
+         IV(SAVEI) = 0
+         GO TO 240
+C
+ 130  IF (IV(TOOBIG) .EQ. 0) GO TO 150
+C        ***  PUNT IN THE EVENT OF AN OVERSIZE STEP  ***
+ 140     IV(FDH) = -2
+         GO TO 350
+ 150  I = IV(SAVEI)
+      IF (I .GT. 0) GO TO 190
+C
+C  ***  SAVE F(X + STP(M)*E(M)) IN H(P,M)  ***
+C
+      PP1O2 = P * (P-1) / 2
+      HPM = HES + PP1O2 + MM1
+      V(HPM) = V(F)
+C
+C  ***  START COMPUTING ROW M OF THE FINITE-DIFFERENCE HESSIAN H.  ***
+C
+      NEWM1 = 1
+      GO TO 260
+ 160  HMI = HES + MM1O2
+      IF (MM1 .EQ. 0) GO TO 180
+      HPI = HES + PP1O2
+      DO 170 I = 1, MM1
+         T = ZERO
+         IF (B(1,I) .LT. B(2,I)) T = V(FX) - (V(F) + V(HPI))
+         V(HMI) = T
+         HMI = HMI + 1
+         HPI = HPI + 1
+ 170     CONTINUE
+ 180  V(HMI) = V(F) - TWO*V(FX)
+      IF (OFFSID) V(HMI) = V(FX) - TWO*V(F)
+C
+C  ***  COMPUTE FUNCTION VALUES NEEDED TO COMPLETE ROW M OF H.  ***
+C
+      I = 0
+      GO TO 200
+C
+ 190  X(I) = V(DELTA)
+C
+C  ***  FINISH COMPUTING H(M,I)  ***
+C
+      STPI = STP0 + I
+      HMI = HES + MM1O2 + I - 1
+      STPM = STP0 + M
+      V(HMI) = (V(HMI) + V(F)) / (V(STPI)*V(STPM))
+ 200  I = I + 1
+      IF (I .GT. M) GO TO 230
+         IF (B(1,I) .LT. B(2,I)) GO TO 210
+         GO TO 200
+C
+ 210  IV(SAVEI) = I
+      STPI = STP0 + I
+      V(DELTA) = X(I)
+      X(I) = X(I) + V(STPI)
+      IRT = 1
+      IF (I .LT. M) GO TO 999
+      NEWM1 = 2
+      GO TO 260
+ 220  X(M) = V(XMSAVE) - DEL
+      IF (OFFSID) X(M) = V(XMSAVE) + TWO*DEL
+      GO TO 999
+C
+ 230  IV(SAVEI) = 0
+      X(M) = V(XMSAVE)
+C
+ 240  M = M + 1
+      IV(MODE) = M
+      IF (M .GT. P) GO TO 330
+      IF (B(1,M) .LT. B(2,M)) GO TO 250
+      GO TO 240
+C
+C  ***  PREPARE TO COMPUTE ROW M OF THE FINITE-DIFFERENCE HESSIAN H.
+C  ***  COMPUTE M-TH STEP SIZE STP(M), THEN RETURN TO OBTAIN
+C  ***  F(X + STP(M)*E(M)), WHERE E(M) = M-TH STD. UNIT VECTOR.
+C
+ 250  V(XMSAVE) = X(M)
+      NEWM1 = 3
+ 260  XM = V(XMSAVE)
+      DEL = V(DLTFDC) * DMAX1(ONE/D(M), DABS(XM))
+      XM1 = XM + DEL
+      OFFSID = .FALSE.
+      IF (XM1 .LE. B(2,M)) GO TO 270
+         OFFSID = .TRUE.
+         XM1 = XM - DEL
+         IF (XM - TWO*DEL .GE. B(1,M)) GO TO 300
+         GO TO 280
+ 270   IF (XM-DEL .GE. B(1,M)) GO TO 290
+       OFFSID = .TRUE.
+       IF (XM + TWO*DEL .LE. B(2,M)) GO TO 310
+C
+ 280  IV(FDH) = -2
+      GO TO 350
+C
+ 290  IF (XM .GE. ZERO) GO TO 310
+      XM1 = XM - DEL
+ 300  DEL = -DEL
+ 310  GO TO (160, 220, 320), NEWM1
+ 320  X(M) = XM1
+      STPM = STP0 + M
+      V(STPM) = DEL
+      IRT = 1
+      GO TO 999
+C
+C  ***  HANDLE SPECIAL CASE OF B(1,P) = B(2,P) -- CLEAR SCRATCH VALUES
+C  ***  FROM LAST ROW OF FDH...
+C
+ 330  IF (B(1,P) .LT. B(2,P)) GO TO 340
+         I = HES + P*(P-1)/2
+         CALL DV7SCP(P, V(I), ZERO)
+C
+C  ***  RESTORE V(F), ETC.  ***
+C
+ 340  IV(FDH) = HES
+ 350  V(F) = V(FX)
+      IRT = 3
+      IF (KIND .LT. 0) GO TO 999
+         IV(NFGCAL) = IV(SWITCH)
+         GSAVE1 = IV(W) + P
+         CALL DV7CPY(P, G, V(GSAVE1))
+         GO TO 999
+C
+ 999  RETURN
+C  ***  LAST LINE OF DF7DHB FOLLOWS  ***
+      END
diff --git a/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/prho.c b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/prho.c
new file mode 100644
index 0000000000000000000000000000000000000000..65a6a9b0d01862349e7868b8bb3a4b44eaa7c194
--- /dev/null
+++ b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/prho.c
@@ -0,0 +1,157 @@
+/*
+ *  R : A Computer Language for Statistical Data Analysis
+ *  Copyright (C) 2000-2016     The R Core Team
+ *  Copyright (C) 2003		The R Foundation
+ *  based on AS 89 (C) 1975 Royal Statistical Society
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, a copy is available at
+ *  https://www.R-project.org/Licenses/
+ *
+ */
+
+#include <math.h>
+#include <Rmath.h>
+
+/* Was
+	double precision function prho(n, is, ifault)
+
+ Changed to subroutine by KH to allow for .Fortran interfacing.
+ Also, change `prho' argument in the code to `pv'.
+ And, fix a bug.
+
+ From R ver. 1.1.x [March, 2000] by MM:
+ - Translate Fortran to C
+ - use pnorm() instead of less precise alnorm().
+ - new argument lower_tail --> potentially increased precision in extreme cases.
+*/
+void
+prho(int n, double is, double *pv, int ifault, int lower_tail)
+{
+/*	Algorithm AS 89	  Appl. Statist. (1975) Vol.24, No. 3, P377.
+
+	To evaluate the probability  Pr[ S >= is ]
+	{or Pr [ S < is]  if(lower_tail) }, where
+
+	S   = (n^3 - n) * (1-R)/6,
+	is  = (n^3 - n) * (1-r)/6,
+	R,r = Spearman's rho (r.v. and observed),  and	n >= 2
+*/
+
+    /* Edgeworth coefficients : */
+    const double
+	c1 = .2274,
+	c2 = .2531,
+	c3 = .1745,
+	c4 = .0758,
+	c5 = .1033,
+	c6 = .3932,
+	c7 = .0879,
+	c8 = .0151,
+	c9 = .0072,
+	c10= .0831,
+	c11= .0131,
+	c12= 4.6e-4;
+
+    /* Local variables */
+    double b, u, x, y, n3;/*, js */
+
+#define n_small 9
+/* originally: n_small = 6 (speed!);
+ * even n_small = 10 (and n = 10) needs quite a bit longer than the approx!
+ * larger than 12 ==> integer overflow in nfac and (probably) ifr
+*/
+    int l[n_small];
+    int nfac, i, m, mt, ifr, ise, n1;
+
+    /* Test admissibility of arguments and initialize */
+    *pv = lower_tail ? 0. : 1.;
+    if (n <= 1) { ifault = 1; return; }
+
+    ifault = 0;
+    if (is <= 0.) return;/* with p = 1 */
+
+    n3 = (double)n;
+    n3 *= (n3 * n3 - 1.) / 3.;/* = (n^3 - n)/3 */
+    if (is > n3) { /* larger than maximal value */
+	*pv = 1 - *pv; return;
+    }
+    /* NOT rounding to even anymore:  with ties, S, may even be non-integer!
+     * js = is;
+     * if(fmod(js, 2.) != 0.) ++js;
+     */
+    if (n <= n_small) { /* 2 <= n <= n_small :
+			  * Exact evaluation of probability */
+	nfac = 1.;
+	for (i = 1; i <= n; ++i) {
+	    nfac *= i;
+	    l[i - 1] = i;
+	}
+	/* KH mod next line: was `!=' in the code but `.eq.' in the paper */
+	if (is == n3) {
+	    ifr = 1;
+	}
+	else {
+	    ifr = 0;
+	    for (m = 0; m < nfac; ++m) {
+		ise = 0;
+		for (i = 0; i < n; ++i) {
+		    n1 = i + 1 - l[i];
+		    ise += n1 * n1;
+		}
+		if (is <= ise)
+		    ++ifr;
+
+		n1 = n;
+		do {
+		    mt = l[0];
+		    for (i = 1; i < n1; ++i)
+			l[i - 1] = l[i];
+		    --n1;
+		    l[n1] = mt;
+		} while (mt == n1+1 && n1 > 1);
+	    }
+	}
+	*pv = (lower_tail ? nfac-ifr : ifr) / (double) nfac;
+    } /* exact for n <= n_small */
+
+    else { /* n >= 7 :	Evaluation by Edgeworth series expansion */
+
+	y = (double) n;
+	b = 1 / y;
+	x = (6. * (is - 1) * b / (y * y - 1) - 1) * sqrt(y - 1);
+	/* = rho * sqrt(n-1)  ==  rho / sqrt(var(rho))  ~  (0,1) */
+	y = x * x;
+	u = x * b * (c1 + b * (c2 + c3 * b) +
+		     y * (-c4 + b * (c5 + c6 * b) -
+			  y * b * (c7 + c8 * b -
+				   y * (c9 - c10 * b + y * b * (c11 - c12 * y))
+			      )));
+	y = u / exp(y / 2.);
+	*pv = (lower_tail ? -y : y) +
+	    pnorm(x, 0., 1., lower_tail, /*log_p = */FALSE);
+	/* above was call to alnorm() [algorithm AS 66] */
+	if (*pv < 0) *pv = 0.;
+	if (*pv > 1) *pv = 1.;
+    }
+    return;
+} /* prho */
+
+#include <Rinternals.h>
+SEXP pRho(SEXP q, SEXP sn, SEXP lower)
+{
+    double s = asReal(q), p;
+    int n = asInteger(sn), ltail = asInteger(lower), ifault = 0;
+    prho(n, s, &p, ifault, ltail);
+    return ScalarReal(p);
+}
diff --git a/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/rWishart.c b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/rWishart.c
new file mode 100644
index 0000000000000000000000000000000000000000..0e14e7c3b04337fc71bbe54f5475b760f63dc1e7
--- /dev/null
+++ b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/rWishart.c
@@ -0,0 +1,119 @@
+/*
+ *  R : A Computer Language for Statistical Data Analysis
+ *  Copyright (C) 2012-2016  The R Core Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, a copy is available at
+ *  https://www.R-project.org/Licenses/
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <math.h>
+#include <string.h>  // memset, memcpy
+#include <R.h>
+#include <Rinternals.h>
+#include <Rmath.h>
+#include <R_ext/Lapack.h>        /* for Lapack (dpotrf, etc.) and BLAS */
+
+#include "stats.h" // for _()
+#include "statsR.h"
+
+
+/**
+ * Simulate the Cholesky factor of a standardized Wishart variate with
+ * dimension p and nu degrees of freedom.
+ *
+ * @param nu degrees of freedom
+ * @param p dimension of the Wishart distribution
+ * @param upper if 0 the result is lower triangular, otherwise upper
+                triangular
+ * @param ans array of size p * p to hold the result
+ *
+ * @return ans
+ */
+static double
+*std_rWishart_factor(double nu, int p, int upper, double ans[])
+{
+    int pp1 = p + 1;
+
+    if (nu < (double) p || p <= 0)
+	error(_("inconsistent degrees of freedom and dimension"));
+
+    memset(ans, 0, p * p * sizeof(double));
+    for (int j = 0; j < p; j++) {	/* jth column */
+	ans[j * pp1] = sqrt(rchisq(nu - (double) j));
+	for (int i = 0; i < j; i++) {
+	    int uind = i + j * p, /* upper triangle index */
+		lind = j + i * p; /* lower triangle index */
+	    ans[(upper ? uind : lind)] = norm_rand();
+	    ans[(upper ? lind : uind)] = 0;
+	}
+    }
+    return ans;
+}
+
+/**
+ * Simulate a sample of random matrices from a Wishart distribution
+ *
+ * @param ns Number of samples to generate
+ * @param nuP Degrees of freedom
+ * @param scal Positive-definite scale matrix
+ *
+ * @return
+ */
+SEXP
+rWishart(SEXP ns, SEXP nuP, SEXP scal)
+{
+    SEXP ans;
+    int *dims = INTEGER(getAttrib(scal, R_DimSymbol)), info,
+	n = asInteger(ns), psqr;
+    double *scCp, *ansp, *tmp, nu = asReal(nuP), one = 1, zero = 0;
+
+    if (!isMatrix(scal) || !isReal(scal) || dims[0] != dims[1])
+	error(_("'scal' must be a square, real matrix"));
+    if (n <= 0) n = 1;
+    // allocate early to avoid memory leaks in Callocs below.
+    PROTECT(ans = alloc3DArray(REALSXP, dims[0], dims[0], n));
+    psqr = dims[0] * dims[0];
+    tmp = Calloc(psqr, double);
+    scCp = Calloc(psqr, double);
+
+    Memcpy(scCp, REAL(scal), psqr);
+    memset(tmp, 0, psqr * sizeof(double));
+    F77_CALL(dpotrf)("U", &(dims[0]), scCp, &(dims[0]), &info);
+    if (info)
+	error(_("'scal' matrix is not positive-definite"));
+    ansp = REAL(ans);
+    GetRNGstate();
+    for (int j = 0; j < n; j++) {
+	double *ansj = ansp + j * psqr;
+	std_rWishart_factor(nu, dims[0], 1, tmp);
+	F77_CALL(dtrmm)("R", "U", "N", "N", dims, dims,
+			&one, scCp, dims, tmp, dims);
+	F77_CALL(dsyrk)("U", "T", &(dims[1]), &(dims[1]),
+			&one, tmp, &(dims[1]),
+			&zero, ansj, &(dims[1]));
+
+	for (int i = 1; i < dims[0]; i++)
+	    for (int k = 0; k < i; k++)
+		ansj[i + k * dims[0]] = ansj[k + i * dims[0]];
+    }
+
+    PutRNGstate();
+    Free(scCp); Free(tmp);
+    UNPROTECT(1);
+    return ans;
+}
diff --git a/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/smooth.c b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/smooth.c
new file mode 100644
index 0000000000000000000000000000000000000000..cec481f0e97e44f3b224054a2aeedf434d4fe51c
--- /dev/null
+++ b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/smooth.c
@@ -0,0 +1,312 @@
+/*
+ *  R : A Computer Language for Statistical Data Analysis
+ *  Copyright (C) 1997-2016   The R Core Team.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, a copy is available at
+ *  https://www.R-project.org/Licenses/
+ */
+
+/* Tukey Median Smoothing */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h> /* for abs */
+#include <math.h>
+
+#include <Rinternals.h> /* Arith.h, Boolean.h, Error.h, Memory.h .. */
+
+typedef enum {
+    sm_NO_ENDRULE, sm_COPY_ENDRULE, sm_TUKEY_ENDRULE
+} R_SM_ENDRULE;
+
+#ifdef ENABLE_NLS
+#include <libintl.h>
+#define _(String) dgettext ("stats", String)
+#else
+#define _(String) (String)
+#endif
+
+static double med3(double u, double v, double w)
+{
+    /* Median(u,v,w): */
+    if((u <= v && v <= w) ||
+       (u >= v && v >= w)) return v;
+    if((u <= w && w <= v) ||
+       (u >= w && w >= v)) return w;
+    /* else */ return u;
+}
+/* Note: Velleman & Hoaglin use a smarter version,  which returns "change"
+   ----
+   and change = TRUE, when  med3(u,v,w) != v   ==> makes "R" (in "3R") faster
+*/
+static int imed3(double u, double v, double w)
+{
+    /* Return (Index-1) of  median(u,v,w) , i.e.,
+       -1 : u
+	0 : v
+	1 : w
+     */
+    if((u <= v && v <= w) ||
+       (u >= v && v >= w)) return 0;
+    if((u <= w && w <= v) ||
+       (u >= w && w >= v)) return 1;
+    /* else */ return -1;
+}
+
+static Rboolean sm_3(double *x, double *y, R_xlen_t n, int end_rule)
+{
+    /* y[] := Running Median of three (x) = "3 (x[])" with "copy ends"
+     * ---  return chg := ( y != x ) */
+    R_xlen_t i;
+    int j;
+    Rboolean chg = FALSE;
+
+    if (n <= 2) {
+        for(i=0; i < n; i++)
+	   y[i] = x[i];
+        return FALSE;
+    }
+
+    for(i = 1; i < n-1; i++) {
+	j = imed3(x[i-1], x[i], x[i+1]);
+	y[i] = x[i + j];
+	chg = chg || j;
+    }
+/* [y, chg]  :=  sm_DO_ENDRULE(x, y, end_rule, chg) : */
+#define sm_DO_ENDRULE(y)						\
+    switch(end_rule) {							\
+    case sm_NO_ENDRULE:							\
+	   /* do nothing : don't even assign them */ break;		\
+									\
+    case sm_COPY_ENDRULE: /* 1 */					\
+	   y[0] = x[0];							\
+	   y[n-1] = x[n-1];						\
+	   break;							\
+									\
+    case sm_TUKEY_ENDRULE: /* 2 */					\
+	   y[0] = med3(3*y[1] - 2*y[2], x[0], y[1]);			\
+	   chg = chg || (y[0] != x[0]);					\
+	   y[n-1] = med3(y[n-2], x[n-1], 3*y[n-2] - 2*y[n-3]);		\
+	   chg = chg || (y[n-1] != x[n-1]);				\
+	   break;							\
+									\
+    default:								\
+	   error(_("invalid end-rule for running median of 3: %d"),	\
+		 end_rule);						\
+    }
+
+    sm_DO_ENDRULE(y);
+
+    return chg;
+}
+
+static int sm_3R(double *x, double *y, double *z, R_xlen_t n, int end_rule)
+{
+    /* y[] := "3R"(x) ; 3R = Median of three, repeated until convergence */
+    int iter;
+    Rboolean chg;
+
+    iter = chg = sm_3(x, y, n, sm_COPY_ENDRULE);
+
+    while(chg) {
+	if((chg = sm_3(y, z, n, sm_NO_ENDRULE))) {
+	    iter++;
+	    for(R_xlen_t i=1; i < n-1; i++)
+		y[i] = z[i];
+	}
+    }
+
+    if (n > 2) sm_DO_ENDRULE(y);/* =>  chg = TRUE  iff  ends changed */
+
+    return(iter ? iter : chg);
+    /* = 0   <==>  only one "3" w/o any change
+       = 1   <==>  either ["3" w/o change + endchange]
+		   or	  [two "3"s, 2nd w/o change  ]
+    */
+}
+
+
+static Rboolean sptest(double *x, R_xlen_t i)
+{
+    /* Split test:
+       Are we at a /-\ or \_/ location => split should be made ?
+     */
+    if(x[i] != x[i+1]) return FALSE;
+    if((x[i-1] <= x[i] && x[i+1] <= x[i+2]) ||
+       (x[i-1] >= x[i] && x[i+1] >= x[i+2])) return FALSE;
+    /* else */ return TRUE;
+}
+
+
+static Rboolean sm_split3(double *x, double *y, R_xlen_t n, Rboolean do_ends)
+{
+    /* y[] := S(x[])  where S() = "sm_split3"  */
+    R_xlen_t i;
+    Rboolean chg = FALSE;
+
+    for(i=0; i < n; i++)
+	y[i] = x[i];
+
+    if (n <= 4) return FALSE;
+
+    /* Colin Goodall doesn't do splits near ends
+       in spl() in Statlib's "smoother" code !! */
+    if(do_ends && sptest(x, 1)) {
+	chg = TRUE;
+	y[1] = x[0];
+	y[2] = med3(x[2], x[3], 3*x[3] - 2*x[4]);
+    }
+
+    for(i=2; i < n-3; i++)
+	if(sptest(x, i)) { /* plateau at x[i] == x[i+1] */
+	    int j;
+	    /* at left : */
+	    if(-1 < (j = imed3(x[i ], x[i-1], 3*x[i-1] - 2*x[i-2]))) {
+		y[i]   = /* med3(.) = */ (j == 0)? x[i-1] : 3*x[i-1] - 2*x[i-2];
+		chg = y[i] != x[i];
+	    }
+	    /* at right : */
+	    if(-1 < (j = imed3(x[i+1], x[i+2], 3*x[i+2] - 2*x[i+3]))) {
+		y[i+1] = /* med3(.) = */ (j == 0)? x[i+2] : 3*x[i+2] - 2*x[i+3];
+		chg = y[i+1] != x[i+1];
+	    }
+	}
+    if(do_ends && sptest(x, n-3)) {
+	chg = TRUE;
+	y[n-2] = x[n-1];
+	y[n-3] = med3(x[n-3], x[n-4], 3*x[n-4] - 2*x[n-5]);
+    }
+    return(chg);
+}
+
+static int sm_3RS3R(double *x, double *y, double *z, double *w, R_xlen_t n,
+	     int end_rule, Rboolean split_ends)
+{
+    /* y[1:n] := "3R S 3R"(x[1:n]);  z = "work"; */
+    int iter;
+    Rboolean chg;
+
+    iter =  sm_3R    (x, y, z, n, end_rule);
+    chg  =  sm_split3(y, z, n, split_ends);
+    if(chg)
+	iter += sm_3R(z, y, w, n, end_rule);
+    /* else y == z already */
+    return(iter + (int)chg);
+}
+
+static int sm_3RSS(double *x, double *y, double *z, R_xlen_t n,
+	    int end_rule, Rboolean split_ends)
+{
+    /* y[1:n] := "3RSS"(x[1:n]);  z = "work"; */
+    int iter;
+    Rboolean chg;
+
+    iter = sm_3R    (x, y, z, n, end_rule);
+    chg =  sm_split3(y, z, n, split_ends);
+    if(chg)
+	sm_split3(z, y, n, split_ends);
+    /* else  y == z already */
+    return(iter + (int)chg);
+}
+
+static int sm_3RSR(double *x, double *y, double *z, double *w, R_xlen_t n,
+	    int end_rule, Rboolean split_ends)
+{
+    /* y[1:n] := "3RSR"(x[1:n]);  z := residuals; w = "work"; */
+
+/*== "SR" (as follows) is stupid ! (MM) ==*/
+
+    R_xlen_t i;
+    int iter;
+    Rboolean chg, ch2;
+
+    iter = sm_3R(x, y, z, n, end_rule);
+
+    do {
+	iter++;
+	chg = sm_split3(y, z, n, split_ends);
+	ch2 = sm_3R(z, y, w, n, end_rule);
+	chg = chg || ch2;
+
+	if(!chg) break;
+	if(iter > 2*n) break;/* INF.LOOP stopper */
+	for(i=0; i < n; i++)
+	    z[i] = x[i] - y[i];
+
+    } while (chg);
+
+    return(iter);
+}
+
+
+/*-------- These are  called from R : -----------*/
+
+#include <Rinternals.h>
+SEXP Rsm(SEXP x, SEXP stype, SEXP send)
+{
+    int iend = asInteger(send), type = asInteger(stype);
+    R_xlen_t n = XLENGTH(x);
+    SEXP ans = PROTECT(allocVector(VECSXP, 2));
+    SEXP y = allocVector(REALSXP, n);
+    SET_VECTOR_ELT(ans, 0, y);
+    SEXP nm = allocVector(STRSXP, 2);
+    setAttrib(ans, R_NamesSymbol, nm);
+    SET_STRING_ELT(nm, 0, mkChar("y"));
+    if (type <= 5) {
+	int iter = 0 /* -Wall */;
+	switch(type){
+	case 1:
+	{
+	    double *z = (double *) R_alloc(n, sizeof(double));
+	    double *w = (double *) R_alloc(n, sizeof(double));
+	    iter = sm_3RS3R(REAL(x), REAL(y), z, w, n, abs(iend),
+			    /* split_ends: */ (iend < 0) ? TRUE : FALSE);
+	    break;
+	}
+	case 2:
+	{
+	    double *z = (double *) R_alloc(n, sizeof(double));
+	    iter = sm_3RSS(REAL(x), REAL(y), z, n, abs(iend),
+			   /* split_ends: */ (iend < 0) ? TRUE : FALSE);
+	    break;
+	}
+	case 3:
+	{
+	    double *z = (double *) R_alloc(n, sizeof(double));
+	    double *w = (double *) R_alloc(n, sizeof(double));
+	    iter = sm_3RSR(REAL(x), REAL(y), z, w, n, abs(iend),
+			   /* split_ends: */ (iend < 0) ? TRUE : FALSE);
+	    break;
+	}
+	case 4: // "3R"
+	{
+	    double *z = (double *) R_alloc(n, sizeof(double));
+	    iter = sm_3R(REAL(x), REAL(y), z, n, iend);
+	}
+	    break;
+	case 5: // "3"
+	    iter = sm_3(REAL(x), REAL(y), n, iend);
+	}
+	SET_VECTOR_ELT(ans, 1, ScalarInteger(iter));
+	SET_STRING_ELT(nm, 1, mkChar("iter"));
+    } else { // type > 5  ==> =~ "S"
+	int changed = sm_split3(REAL(x), REAL(y), n, (Rboolean) iend);
+	SET_VECTOR_ELT(ans, 1, ScalarLogical(changed));
+	SET_STRING_ELT(nm, 1, mkChar("changed"));
+    }
+    UNPROTECT(1);
+    return ans;
+}
diff --git a/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/starma.c b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/starma.c
new file mode 100644
index 0000000000000000000000000000000000000000..1b17de1fe1a97dfd4858193e86750590e98ecb3b
--- /dev/null
+++ b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/starma.c
@@ -0,0 +1,521 @@
+/*  R : A Computer Language for Statistical Data Analysis
+ *
+ *  Copyright (C) 1999-2002 The R Core Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, a copy is available at
+ *  https://www.R-project.org/Licenses/.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <R.h>
+#include "ts.h"
+
+
+#ifndef max
+#define max(a,b) ((a < b)?(b):(a))
+#endif
+#ifndef min
+#define min(a,b) ((a > b)?(b):(a))
+#endif
+
+/* Code in this file based on Applied Statistics algorithms AS154/182
+   (C) Royal Statistical Society 1980, 1982 */
+
+static void
+inclu2(int np, double *xnext, double *xrow, double ynext,
+       double *d, double *rbar, double *thetab)
+{
+    double cbar, sbar, di, xi, xk, rbthis, dpi;
+    int i, k, ithisr;
+
+/*   This subroutine updates d, rbar, thetab by the inclusion
+     of xnext and ynext. */
+
+    for (i = 0; i < np; i++) xrow[i] = xnext[i];
+
+    for (ithisr = 0, i = 0; i < np; i++) {
+	if (xrow[i] != 0.0) {
+	    xi = xrow[i];
+	    di = d[i];
+	    dpi = di + xi * xi;
+	    d[i] = dpi;
+	    cbar = di / dpi;
+	    sbar = xi / dpi;
+	    for (k = i + 1; k < np; k++) {
+		xk = xrow[k];
+		rbthis = rbar[ithisr];
+		xrow[k] = xk - xi * rbthis;
+		rbar[ithisr++] = cbar * rbthis + sbar * xk;
+	    }
+	    xk = ynext;
+	    ynext = xk - xi * thetab[i];
+	    thetab[i] = cbar * thetab[i] + sbar * xk;
+	    if (di == 0.0) return;
+	} else ithisr = ithisr + np - i - 1;
+    }
+}
+
+void starma(Starma G, int *ifault)
+{
+    int p = G->p, q = G->q, r = G->r, np = G->np, nrbar = G->nrbar;
+    double *phi = G->phi, *theta = G->theta, *a = G->a,
+	*P = G->P, *V = G->V, *thetab = G->thetab, *xnext = G->xnext,
+	*xrow = G->xrow, *rbar = G->rbar;
+    int indi, indj, indn;
+    double phii, phij, ynext, vj, bi;
+    int i, j, k, ithisr, ind, npr, ind1, ind2, npr1, im, jm;
+
+/*      Invoking this subroutine sets the values of v and phi, and
+	obtains the initial values of a and p. */
+
+/*     Check if ar(1) */
+
+    if (!(q > 0 || p > 1)) {
+	V[0] = 1.0;
+	a[0] = 0.0;
+	P[0] = 1.0 / (1.0 - phi[0] * phi[0]);
+	return;
+    }
+
+/*        Check for failure indication. */
+    *ifault = 0;
+    if (p < 0) *ifault = 1;
+    if (q < 0) *ifault += 2;
+    if (p == 0 && q == 0) *ifault = 4;
+    k = q + 1;
+    if (k < p) k = p;
+    if (r != k) *ifault = 5;
+    if (np != r * (r + 1) / 2) *ifault = 6;
+    if (nrbar != np * (np - 1) / 2) *ifault = 7;
+    if (r == 1) *ifault = 8;
+    if (*ifault != 0) return;
+
+/*        Now set a(0), V and phi. */
+
+    for (i = 1; i < r; i++) {
+	a[i] = 0.0;
+	if (i >= p) phi[i] = 0.0;
+	V[i] = 0.0;
+	if (i < q + 1) V[i] = theta[i - 1];
+    }
+    a[0] = 0.0;
+    if (p == 0) phi[0] = 0.0;
+    V[0] = 1.0;
+    ind = r;
+    for (j = 1; j < r; j++) {
+	vj = V[j];
+	for (i = j; i < r; i++) V[ind++] = V[i] * vj;
+    }
+
+/*        Now find p(0). */
+
+    if (p > 0) {
+/*      The set of equations s * vec(p(0)) = vec(v) is solved for
+	vec(p(0)).  s is generated row by row in the array xnext.  The
+	order of elements in p is changed, so as to bring more leading
+	zeros into the rows of s. */
+
+	for (i = 0; i < nrbar; i++) rbar[i] = 0.0;
+	for (i = 0; i < np; i++) {
+	    P[i] = 0.0;
+	    thetab[i] = 0.0;
+	    xnext[i] = 0.0;
+	}
+	ind = 0;
+	ind1 = -1;
+	npr = np - r;
+	npr1 = npr + 1;
+	indj = npr;
+	ind2 = npr - 1;
+	for (j = 0; j < r; j++) {
+	    phij = phi[j];
+	    xnext[indj++] = 0.0;
+	    indi = npr1 + j;
+	    for (i = j; i < r; i++) {
+		ynext = V[ind++];
+		phii = phi[i];
+		if (j != r - 1) {
+		    xnext[indj] = -phii;
+		    if (i != r - 1) {
+			xnext[indi] -= phij;
+			xnext[++ind1] = -1.0;
+		    }
+		}
+		xnext[npr] = -phii * phij;
+		if (++ind2 >= np) ind2 = 0;
+		xnext[ind2] += 1.0;
+		inclu2(np, xnext, xrow, ynext, P, rbar, thetab);
+		xnext[ind2] = 0.0;
+		if (i != r - 1) {
+		    xnext[indi++] = 0.0;
+		    xnext[ind1] = 0.0;
+		}
+	    }
+	}
+
+	ithisr = nrbar - 1;
+	im = np - 1;
+	for (i = 0; i < np; i++) {
+	    bi = thetab[im];
+	    for (jm = np - 1, j = 0; j < i; j++)
+		bi -= rbar[ithisr--] * P[jm--];
+	    P[im--] = bi;
+	}
+
+/*        now re-order p. */
+
+	ind = npr;
+	for (i = 0; i < r; i++) xnext[i] = P[ind++];
+	ind = np - 1;
+	ind1 = npr - 1;
+	for (i = 0; i < npr; i++) P[ind--] = P[ind1--];
+	for (i = 0; i < r; i++) P[i] = xnext[i];
+    } else {
+
+/* P(0) is obtained by backsubstitution for a moving average process. */
+
+	indn = np;
+	ind = np;
+	for (i = 0; i < r; i++)
+	    for (j = 0; j <= i; j++) {
+		--ind;
+		P[ind] = V[ind];
+		if (j != 0) P[ind] += P[--indn];
+	    }
+    }
+}
+
+void karma(Starma G, double *sumlog, double *ssq, int iupd, int *nit)
+{
+    int p = G->p, q = G->q, r = G->r, n = G->n, nu = 0;
+    double *phi = G->phi, *theta = G->theta, *a = G->a, *P = G->P,
+	*V = G->V, *w = G->w, *resid = G->resid, *work = G->xnext;
+
+    int i, j, l, ii, ind, indn, indw;
+    double a1, dt, et, ft, g, ut, phij, phijdt;
+
+/*  Invoking this subroutine updates a, P, sumlog and ssq by inclusion
+    of data values w(1) to w(n). the corresponding values of resid are
+    also obtained.  When ft is less than (1 + delta), quick recursions
+    are used. */
+
+/*        for non-zero values of nit, perform quick recursions. */
+
+    if (*nit == 0) {
+	for (i = 0; i < n; i++) {
+
+/*        prediction. */
+
+	    if (iupd != 1 || i > 0) {
+
+/*        here dt = ft - 1.0 */
+
+		dt = (r > 1) ? P[r] : 0.0;
+		if (dt < G->delta) goto L610;
+		a1 = a[0];
+		for (j = 0; j < r - 1; j++) a[j] = a[j + 1];
+		a[r - 1] = 0.0;
+		for (j = 0; j < p; j++) a[j] += phi[j] * a1;
+		if(P[0] == 0.0) { /* last obs was available */
+		    ind = -1;
+		    indn = r;
+		    for (j = 0; j < r; j++)
+			for (l = j; l < r; l++) {
+			    ++ind;
+			    P[ind] = V[ind];
+			    if (l < r - 1) P[ind] += P[indn++];
+			}
+		} else {
+		    for (j = 0; j < r; j++) work[j] = P[j];
+		    ind = -1;
+		    indn = r;
+		    dt = P[0];
+		    for (j = 0; j < r; j++) {
+			phij = phi[j];
+			phijdt = phij * dt;
+			for(l = j; l < r; l++) {
+			    ++ind;
+			    P[ind] = V[ind] + phi[l] * phijdt;
+			    if (j < r - 1) P[ind] += work[j+1] * phi[l];
+			    if (l < r - 1)
+				P[ind] += work[l+1] * phij + P[indn++];
+			}
+		    }
+		}
+	    }
+
+/*        updating. */
+
+	    ft = P[0];
+	    if(!ISNAN(w[i])) {
+		ut = w[i] - a[0];
+		if (r > 1)
+		    for (j = 1, ind = r; j < r; j++) {
+			g = P[j] / ft;
+			a[j] += g * ut;
+			for (l = j; l < r; l++) P[ind++] -= g * P[l];
+		    }
+		a[0] = w[i];
+		resid[i] = ut / sqrt(ft);
+		*ssq += ut * ut / ft;
+		*sumlog += log(ft);
+		nu++;
+		for (l = 0; l < r; l++) P[l] = 0.0;
+	    } else resid[i] = NA_REAL;
+
+	}
+	*nit = n;
+
+    } else {
+
+/*        quick recursions: never used with missing values */
+
+	i = 0;
+ L610:
+	*nit = i;
+	for (ii = i; ii < n; ii++) {
+	    et = w[ii];
+	    indw = ii;
+	    for (j = 0; j < p; j++) {
+		if (--indw < 0) break;
+		et -= phi[j] * w[indw];
+	    }
+	    for (j = 0; j < min(ii, q); j++)
+		et -= theta[j] * resid[ii - j - 1];
+	    resid[ii] = et;
+	    *ssq += et * et;
+	    nu++;
+	}
+    }
+    G->nused = nu;
+}
+
+
+/*  start of AS 182 */
+void
+forkal(Starma G, int d, int il, double *delta, double *y, double *amse,
+       int *ifault)
+{
+    int p = G->p, q = G->q, r = G->r, n = G->n, np = G->np;
+    double *phi = G->phi, *V = G->V, *w = G->w, *xrow = G->xrow;
+    double *a, *P, *store;
+    int rd = r + d, rz = rd*(rd + 1)/2;
+    double phii, phij, sigma2, a1, aa, dt, phijdt, ams, tmp;
+    int i, j, k, l, nu = 0;
+    int k1;
+    int i45, jj, kk, lk, ll;
+    int nt;
+    int kk1, lk1;
+    int ind, jkl, kkk;
+    int ind1, ind2;
+
+/*  Finite sample prediction from ARIMA processes. */
+
+/*  This routine will calculate the finite sample predictions
+    and their conditional mean square errors for any ARIMA process. */
+
+/*     invoking this routine will calculate the finite sample predictions */
+/*     and their conditional mean square errors for any arima process. */
+
+    store = (double *) R_alloc(rd, sizeof(double));
+    Free(G->a); G->a = a = Calloc(rd, double);
+    Free(G->P); G->P = P = Calloc(rz, double);
+
+/*     check for input faults. */
+    *ifault = 0;
+    if (p < 0) *ifault = 1;
+    if (q < 0) *ifault += 2;
+    if (p * p + q * q == 0) *ifault = 4;
+    if (r != max(p, q + 1)) *ifault = 5;
+    if (np != r * (r + 1) / 2) *ifault = 6;
+    if (d < 0) *ifault = 8;
+    if (il < 1) *ifault = 11;
+    if (*ifault != 0) return;
+
+/*     Find initial likelihood conditions. */
+
+    if (r == 1) {
+	a[0] = 0.0;
+	V[0] = 1.0;
+	P[0] = 1.0 / (1.0 - phi[0] * phi[0]);
+    } else starma(G, ifault);
+
+/*     Calculate data transformations */
+
+    nt = n - d;
+    if (d > 0) {
+	for (j = 0; j < d; j++) {
+	    store[j] = w[n - j - 2];
+	    if(ISNAN(store[j]))
+		error(_("missing value in last %d observations"), d);
+	}
+	for (i = 0; i < nt; i++) {
+	    aa = 0.0;
+	    for (k = 0; k < d; ++k) aa -= delta[k] * w[d + i - k - 1];
+	    w[i] = w[i + d] + aa;
+	}
+    }
+
+/*     Evaluate likelihood to obtain final Kalman filter conditions */
+
+    {
+	double sumlog = 0.0, ssq = 0.0;
+	int nit = 0;
+	G->n = nt;
+	karma(G, &sumlog, &ssq, 1, &nit);
+    }
+
+
+/*     Calculate m.l.e. of sigma squared */
+
+    sigma2 = 0.0;
+    for (j = 0; j < nt; j++) {
+	/* macOS/gcc 3.5 didn't have isnan defined properly */
+	tmp = G->resid[j];
+	if(!ISNAN(tmp)) { nu++; sigma2 += tmp * tmp; }
+    }
+
+    sigma2 /= nu;
+
+/*     reset the initial a and P when differencing occurs */
+
+    if (d > 0) {
+	for (i = 0; i < np; i++) xrow[i] = P[i];
+	for (i = 0; i < rz; i++) P[i] = 0.0;
+	ind = 0;
+	for (j = 0; j < r; j++) {
+	    k = j * (rd + 1) - j * (j + 1) / 2;
+	    for (i = j; i < r; i++) P[k++] = xrow[ind++];
+	}
+	for (j = 0; j < d; j++) a[r + j] = store[j];
+    }
+
+    i45 = 2*rd + 1;
+    jkl = r * (2*d + r + 1) / 2;
+
+    for (l = 0; l < il; ++l) {
+
+/*     predict a */
+
+	a1 = a[0];
+	for (i = 0; i < r - 1; i++) a[i] = a[i + 1];
+	a[r - 1] = 0.0;
+	for (j = 0; j < p; j++) a[j] += phi[j] * a1;
+	if (d > 0) {
+	    for (j = 0; j < d; j++) a1 += delta[j] * a[r + j];
+	    for (i = rd - 1; i > r; i--) a[i] = a[i - 1];
+	    a[r] = a1;
+	}
+
+/*     predict P */
+
+	if (d > 0) {
+	    for (i = 0; i < d; i++) {
+		store[i] = 0.0;
+		for (j = 0; j < d; j++) {
+		    ll = max(i, j);
+		    k = min(i, j);
+		    jj = jkl + (ll - k) + k * (2*d + 2 - k - 1) / 2;
+		    store[i] += delta[j] * P[jj];
+		}
+	    }
+	    if (d > 1) {
+		for (j = 0; j < d - 1; j++) {
+		    jj = d - j - 1;
+		    lk = (jj - 1) * (2*d + 2 - jj) / 2 + jkl;
+		    lk1 = jj * (2*d + 1 - jj) / 2 + jkl;
+		    for (i = 0; i <= j; i++) P[lk1++] = P[lk++];
+		}
+		for (j = 0; j < d - 1; j++)
+		    P[jkl + j + 1] = store[j] + P[r + j];
+	    }
+	    P[jkl] = P[0];
+	    for (i = 0; i < d; i++)
+		P[jkl] += delta[i] * (store[i] + 2.0 * P[r + i]);
+	    for (i = 0; i < d; i++) store[i] = P[r + i];
+	    for (j = 0; j < r; j++) {
+		kk1 = (j+1) * (2*rd - j - 2) / 2 + r;
+		k1 = j * (2*rd - j - 1) / 2 + r;
+		for (i = 0; i < d; i++) {
+		    kk = kk1 + i;
+		    k = k1 + i;
+		    P[k] = phi[j] * store[i];
+		    if (j < r - 1) P[k] += P[kk];
+		}
+	    }
+
+	    for (j = 0; j < r; j++) {
+		store[j] = 0.0;
+		kkk = (j + 1) * (i45 - j - 1) / 2 - d;
+		for (i = 0; i < d; i++) store[j] += delta[i] * P[kkk++];
+	    }
+	    for (j = 0; j < r; j++) {
+		k = (j + 1) * (rd + 1) - (j + 1) * (j + 2) / 2;
+		for (i = 0; i < d - 1; i++) {
+		    --k;
+		    P[k] = P[k - 1];
+		}
+	    }
+	    for (j = 0; j < r; j++) {
+		k = j * (2*rd - j - 1) / 2 + r;
+		P[k] = store[j] + phi[j] * P[0];
+		if (j < r - 1) P[k] += P[j + 1];
+	    }
+	}
+	for (i = 0; i < r; i++) store[i] = P[i];
+
+	ind = 0;
+	dt = P[0];
+	for (j = 0; j < r; j++) {
+	    phij = phi[j];
+	    phijdt = phij * dt;
+	    ind2 = j * (2*rd - j + 1) / 2 - 1;
+	    ind1 = (j + 1) * (i45 - j - 1) / 2 - 1;
+	    for (i = j; i < r; i++) {
+		++ind2;
+		phii = phi[i];
+		P[ind2] = V[ind++] + phii * phijdt;
+		if (j < r - 1) P[ind2] += store[j + 1] * phii;
+		if (i < r - 1)
+		    P[ind2] += store[i + 1] * phij + P[++ind1];
+	    }
+	}
+
+/*     predict y */
+
+	y[l] = a[0];
+	for (j = 0; j < d; j++) y[l] += a[r + j] * delta[j];
+
+/*     calculate m.s.e. of y */
+
+	ams = P[0];
+	if (d > 0) {
+	    for (j = 0; j < d; j++) {
+		k = r * (i45 - r) / 2 + j * (2*d + 1 - j) / 2;
+		tmp = delta[j];
+		ams += 2.0 * tmp * P[r + j] + P[k] * tmp * tmp;
+	    }
+	    for (j = 0; j < d - 1; j++) {
+		k = r * (i45 - r) / 2 + 1 + j * (2*d + 1 - j) / 2;
+		for (i = j + 1; i < d; i++)
+		    ams += 2.0 * delta[i] * delta[j] * P[k++];
+	    }
+	}
+	amse[l] = ams * sigma2;
+    }
+    return;
+}
diff --git a/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/swilk.c b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/swilk.c
new file mode 100644
index 0000000000000000000000000000000000000000..263ee6058708c79db4ef0ee61327b96f32cccf14
--- /dev/null
+++ b/com.oracle.truffle.r.native/gnur/patch/src/library/stats/src/swilk.c
@@ -0,0 +1,214 @@
+/*
+ *  R : A Computer Language for Statistical Data Analysis
+ *  Copyright (C) 2000-2016   The R Core Team.
+ *
+ *  Based on Applied Statistics algorithms AS181, R94
+ *    (C) Royal Statistical Society 1982, 1995
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, a copy is available at
+ *  https://www.R-project.org/Licenses/
+ */
+
+/* swilk.f -- translated by f2c (version 19980913).
+ * ------- and produced by f2c-clean,v 1.8 --- and hand polished: M.Maechler
+ */
+
+#include <math.h>
+#include <Rmath.h>
+
+#ifndef min
+# define min(a, b)		((a) > (b) ? (b) : (a))
+#endif
+
+static double poly(const double *, int, double);
+
+static void
+swilk(double *x, int n, double *w, double *pw, int *ifault)
+{
+    int nn2 = n / 2;
+    double a[nn2 + 1]; /* 1-based */
+
+/*	ALGORITHM AS R94 APPL. STATIST. (1995) vol.44, no.4, 547-551.
+
+	Calculates the Shapiro-Wilk W test and its significance level
+*/
+
+    double small = 1e-19;
+
+    /* polynomial coefficients */
+    double g[2] = { -2.273,.459 };
+    double c1[6] = { 0.,.221157,-.147981,-2.07119, 4.434685, -2.706056 };
+    double c2[6] = { 0.,.042981,-.293762,-1.752461,5.682633, -3.582633 };
+    double c3[4] = { .544,-.39978,.025054,-6.714e-4 };
+    double c4[4] = { 1.3822,-.77857,.062767,-.0020322 };
+    double c5[4] = { -1.5861,-.31082,-.083751,.0038915 };
+    double c6[3] = { -.4803,-.082676,.0030302 };
+
+    /* Local variables */
+    int i, j, i1;
+
+    double ssassx, summ2, ssumm2, gamma, range;
+    double a1, a2, an, m, s, sa, xi, sx, xx, y, w1;
+    double fac, asa, an25, ssa, sax, rsn, ssx, xsx;
+
+    *pw = 1.;
+    if (n < 3) { *ifault = 1; return;}
+
+    an = (double) n;
+
+    if (n == 3) {
+	a[1] = 0.70710678;/* = sqrt(1/2) */
+    } else {
+	an25 = an + .25;
+	summ2 = 0.;
+	for (i = 1; i <= nn2; i++) {
+	    a[i] = qnorm((i - 0.375) / an25, 0., 1., 1, 0);
+	    double r__1 = a[i];
+	    summ2 += r__1 * r__1;
+	}
+	summ2 *= 2.;
+	ssumm2 = sqrt(summ2);
+	rsn = 1. / sqrt(an);
+	a1 = poly(c1, 6, rsn) - a[1] / ssumm2;
+
+	/* Normalize a[] */
+	if (n > 5) {
+	    i1 = 3;
+	    a2 = -a[2] / ssumm2 + poly(c2, 6, rsn);
+	    fac = sqrt((summ2 - 2. * (a[1] * a[1]) - 2. * (a[2] * a[2]))
+		       / (1. - 2. * (a1 * a1) - 2. * (a2 * a2)));
+	    a[2] = a2;
+	} else {
+	    i1 = 2;
+	    fac = sqrt((summ2 - 2. * (a[1] * a[1])) /
+		       ( 1.  - 2. * (a1 * a1)));
+	}
+	a[1] = a1;
+	for (i = i1; i <= nn2; i++) a[i] /= - fac;
+    }
+
+/*	Check for zero range */
+
+    range = x[n - 1] - x[0];
+    if (range < small) {*ifault = 6; return;}
+
+/*	Check for correct sort order on range - scaled X */
+
+    /* *ifault = 7; <-- a no-op, since it is changed below, in ANY CASE! */
+    *ifault = 0;
+    xx = x[0] / range;
+    sx = xx;
+    sa = -a[1];
+    for (i = 1, j = n - 1; i < n; j--) {
+	xi = x[i] / range;
+	if (xx - xi > small) {
+	    /* Fortran had:	 print *, "ANYTHING"
+	     * but do NOT; it *does* happen with sorted x (on Intel GNU/linux 32bit):
+	     *  shapiro.test(c(-1.7, -1,-1,-.73,-.61,-.5,-.24, .45,.62,.81,1))
+	     */
+	    *ifault = 7;
+	}
+	sx += xi;
+	i++;
+	if (i != j) sa += sign(i - j) * a[min(i, j)];
+	xx = xi;
+    }
+    if (n > 5000) *ifault = 2;
+
+/*	Calculate W statistic as squared correlation
+	between data and coefficients */
+
+    sa /= n;
+    sx /= n;
+    ssa = ssx = sax = 0.;
+    for (i = 0, j = n - 1; i < n; i++, j--) {
+	if (i != j) asa = sign(i - j) * a[1 + min(i, j)] - sa; else asa = -sa;
+	xsx = x[i] / range - sx;
+	ssa += asa * asa;
+	ssx += xsx * xsx;
+	sax += asa * xsx;
+    }
+
+/*	W1 equals (1-W) calculated to avoid excessive rounding error
+	for W very near 1 (a potential problem in very large samples) */
+
+    ssassx = sqrt(ssa * ssx);
+    w1 = (ssassx - sax) * (ssassx + sax) / (ssa * ssx);
+    *w = 1. - w1;
+
+/*	Calculate significance level for W */
+
+    if (n == 3) {/* exact P value : */
+	double pi6 = 1.90985931710274, /* = 6/pi */
+	    stqr = 1.04719755119660; /* = asin(sqrt(3/4)) */
+	*pw = pi6 * (asin(sqrt(*w)) - stqr);
+	if(*pw < 0.) *pw = 0.;
+	return;
+    }
+    y = log(w1);
+    xx = log(an);
+    if (n <= 11) {
+	gamma = poly(g, 2, an);
+	if (y >= gamma) {
+	    *pw = 1e-99;/* an "obvious" value, was 'small' which was 1e-19f */
+	    return;
+	}
+	y = -log(gamma - y);
+	m = poly(c3, 4, an);
+	s = exp(poly(c4, 4, an));
+    } else {/* n >= 12 */
+	m = poly(c5, 4, xx);
+	s = exp(poly(c6, 3, xx));
+    }
+    /*DBG printf("c(w1=%g, w=%g, y=%g, m=%g, s=%g)\n",w1,*w,y,m,s); */
+
+    *pw = pnorm(y, m, s, 0/* upper tail */, 0);
+
+    return;
+} /* swilk */
+
+static double poly(const double *cc, int nord, double x)
+{
+/* Algorithm AS 181.2	Appl. Statist.	(1982) Vol. 31, No. 2
+
+	Calculates the algebraic polynomial of order nord-1 with
+	array of coefficients cc.  Zero order coefficient is cc(1) = cc[0]
+*/
+    double p, ret_val;
+
+    ret_val = cc[0];
+    if (nord > 1) {
+	p = x * cc[nord-1];
+	for (int j = nord - 2; j > 0; j--) p = (p + cc[j]) * x;
+	ret_val += p;
+    }
+    return ret_val;
+} /* poly */
+
+
+#include <Rinternals.h>
+SEXP SWilk(SEXP x)
+{
+    int n, ifault = 0;
+    double W = 0, pw;  /* original version tested W on entry */
+    x = PROTECT(coerceVector(x, REALSXP));
+    n = LENGTH(x);
+    swilk(REAL(x), n, &W, &pw, &ifault);
+    if (ifault > 0 && ifault != 7)
+	error("ifault=%d. This should not happen", ifault);
+    SEXP ans = PROTECT(allocVector(REALSXP, 2));
+    REAL(ans)[0] = W, REAL(ans)[1] = pw;
+    UNPROTECT(2);
+    return ans;
+}