/*--------------------------------------------------------------------
 *	$Id: gmt_vector.c,v 1.2.4.1 2002/01/17 17:42:51 pwessel Exp $
 *
 *	Copyright (c) 1991-2002 by P. Wessel and W. H. F. Smith
 *	See COPYING file for copying and redistribution conditions.
 *
 *	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; version 2 of the License.
 *
 *	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.
 *
 *	Contact info: gmt.soest.hawaii.edu
 *--------------------------------------------------------------------*/

/*
 * Author:	Walter H.F. Smith
 * Date:	12-JUL-2000
 * Version:	3.4.1
 */
 
#include "gmt.h"

#define MAX_SWEEPS 50

int	GMT_jacobi (double *a, int *n, int *m, double *d, double *v, double *b, double *z, int *nrots) {
/*
 *
 * Find eigenvalues & eigenvectors of a square symmetric matrix by Jacobi's
 * method.  Given A, find V and D such that A = V * D * V-transpose, with
 * V an orthogonal matrix and D a diagonal matrix.  The eigenvalues of A
 * are on diag(D), and the j-th column of V is the eigenvector corresponding
 * to the j-th diagonal element of D.  Returns 0 if OK, -1 if it fails to
 * converge in MAX_SWEEPS.
 *
 * a is sent as a square symmetric matrix, of size n, and row dimension m.
 * Only the diagonal and super-diagonal elements of a will be used, so the
 * sub-diagonal elements could be used to preserve a, or could have been
 * destroyed by an earlier attempt to form the Cholesky decomposition of a.
 * On return, the super-diagonal elements are destroyed.  The diagonal and
 * sub-diagonal elements are unchanged.
 * d is returned as an n-vector containing the eigenvalues of a, sorted 
 * so that d[i] >= d[j] when i < j.  d = diag(D).
 * v is returned as an n by n matrix, V, with row dimension m, and the
 * columns of v are the eigenvectors corresponding to the values in d.
 * b is an n-vector of workspace, used to keep a copy of the diagonal
 * elements which is updated only after a full sweep.  
 * z is an n-vector of workspace, used to accumulate the updates to
 * the diagonal values of a during each sweep.  This reduces round-
 * off problems.
 * nrots is the number of rotations performed.  Bounds on round-off error
 * can be estimated from this if desired.
 *
 * Numerical Details:
 * The basic algorithms is in many textbooks.  The idea is to make an
 * infinite series (which turns out to be at quadratically convergent)
 * of steps, in each of which A_new = P-transpose * A_old * P, where P is
 * a plane-rotation matrix in the p,q plane, through an angle chosen to
 * zero A_new(p,q) and A_new(q,p).  The sum of the diagonal elements
 * of A is unchanged by these operations, but the sum of squares of 
 * diagonal elements of a is increased by 2 * |A_old(p,q)| at each step.
 * Although later steps make non-zero again the previously zeroed entries,
 * the sum of squares of diagonal elements increases with each rotation,
 * while the sum of squares of off-diagonals keeps decreasing, so that
 * eventually A_new is diagonal to machine precision.  This should 
 * happen in a few (3 to 7) sweeps.
 *
 * If only the eigenvalues are wanted then there are faster methods, but
 * if all eigenvalues and eigenvectors are needed, then this method is
 * only somewhat slower than the fastest method (Householder tri-
 * diagonalization followed by symmetric QR iterations), and this method
 * is numerically extremely stable.
 *
 * C G J Jacobi ("Ueber ein leichtes Vefahren, die in der Theorie der 
 * Saekularstoerungen vorkommenden Gelichungen numerisch aufzuloesen",
 * Crelle's Journal, v. 30, pp. 51--94, 1846) originally searched the
 * entire (half) matrix for the largest |A(p,q)| to select each step.
 * When the method was developed for machine computation (R T Gregory,
 * "Computing eigenvalues and eigenvectors of a symmetric matrix on
 * the ILLIAC", Math. Tab. and other Aids to Comp., v. 7, pp. 215--220,
 * 1953) it was done with a series of "sweeps" through the upper triangle,
 * visiting all p,q in turn.  Later, D A Pope and C Tompkins ("Maximizing
 * functions of rotations - experiments concerning speed of diagonalization
 * of symmetric matrices using Jacobi's method", J Assoc. Comput. Mach.
 * v. 4, pp. 459--466, 1957) introduced a variant that skips small
 * elements on the first few sweeps.  The algorithm here was given by 
 * Heinz Rutishauser (1918--1970) and published in Numer. Math. v. 9, 
 * pp 1--10, 1966, and in Linear Algebra (the Handbook for Automatic 
 * Computation, v. II), by James Hardy Wilkinson and C. Reinsch (Springer-
 * Verlag, 1971).  It also appears in Numerical Recipes.
 *
 * This algorithm takes care to avoid round-off error in several ways.
 * First, although there are four values of theta in (-pi, pi] that
 * would zero A(p,q), there is only one with magnitude <= pi/4.
 * This one is used.  This is most stable, and also has the effect
 * that, if A_old(p,p) >= A_old(q,q) then A_new(p,p) > A_new(q,q).
 * Two copies of the diagonal elements are maintained in d[] and b[].
 * d[] is updated immediately in each rotation, and each new rotation
 * is computed based on d[], so that each rotation gets the benefit
 * of the previous ones.  However, z[] is also used to accumulate
 * the sum of all the changes in the diagonal elements during one sweep, 
 * and z[] is used to update b[] after each sweep.  Then b is copied
 * to d.  In this way, at the end of each sweep, d is reset to avoid
 * accumulating round-off.
 *
 * This routine determines whether y is small compared to x by testing
 * if (fabs(y) + fabs(x) == fabs(x) ).  It is assumed that the
 * underflow which may occur here is nevertheless going to allow this
 * expression to be evaluated as TRUE or FALSE and execution to 
 * continue.  If the run environment doesn't allow this, the routine
 * won't work properly.
 *
 * programmer:	W. H. F. Smith, 7 June, 1991.
 * Revised:	PW: 12-MAR-1998 for GMT 3.1
 * Revision by WHF Smith, March 03, 2000, to speed up loop indexes.
 */
	int	p, q, pp, pq, mp1, pm, qm, nsweeps, j, jm, i, k;
	double	sum, threshold, g, h, t, theta, c, s, tau;


	/* Begin by initializing v, b, d, and z.  v = identity matrix,
		b = d = diag(a), and z = 0:  */
	
	memset ((void *)v, 0, (size_t)((*m)*(*n)*sizeof(double)) );
	memset ((void *)z, 0, (size_t)((*n)*sizeof(double)) );
	
	mp1 = (*m) + 1;
	
	for (p = 0, pp = 0; p < (*n); p++, pp+=mp1) {
		v[pp] = 1.0;
		b[p] = a[pp];
		d[p] = b[p];
	}

	/* End of initializations.  Set counters and begin:  */

	(*nrots) = 0;
	nsweeps = 0;

	while (nsweeps < MAX_SWEEPS) {
	
		/* Sum off-diagonal elements of upper triangle.  */
		sum = 0.0;
		for (q = 1, qm = (*m); q < (*n); q++, qm += (*m) ) {
			for (p = 0, pq = qm; p < q; p++, pq++) {
				sum += fabs(a[pq]);
			}
		}
		
		/* Exit this loop (converged) when sum == 0.0  */
		if (sum == 0.0) break;


		/* If (nsweeps < 3) do only bigger elements;  else all  */
		threshold =  (nsweeps < 3) ? 0.2 * sum / ( (*n) * (*n) ) : 0.0;

		/* Now sweep whole upper triangle doing Givens rotations:  */
		
		for (q = 1, qm = (*m); q < (*n); q++, qm += (*m) ) {
			for (p = 0, pm = 0, pq = qm; p < q; p++, pm += (*m), pq++) {
				/* In 3/2000 I swapped order of these loops,
					to allow simple incrementing of pq  */
			
				if (a[pq] == 0.0) continue;	/* New 3/2000  */
			
				g = 100.0 * fabs(a[pq]);
				
				/* After four sweeps, if g is small relative
					to a(p,p) and a(q,q), skip the 
					rotation and set a(p,q) to zero.  */

				if ( (nsweeps > 3) && ( (fabs(d[p])+g) == fabs(d[p]) ) && ( (fabs(d[q])+g) == fabs(d[q]) ) ) {
					a[pq] = 0.0;
				}
				else if (fabs(a[pq]) > threshold) {

					h = d[q] - d[p];
					
					if (h == 0.0) {
						t = 1.0;	/* This if block is new 3/2000  */
					}
					else if ( (fabs(h)+g) ==  fabs(h) ) {
						t = a[pq] / h;
					}
					else {
						theta = 0.5 * h / a[pq];
						t = 1.0 / (fabs(theta) + sqrt(1.0 + theta*theta) );
						if (theta < 0.0) t = -t;
					}

					c = 1.0 / sqrt(1.0 + t*t);
					s = t * c;
					tau = s / (1.0 + c);
					
					h = t * a[pq];
					z[p] -= h;
					z[q] += h;
					d[p] -= h;
					d[q] += h;
					a[pq] = 0.0;

					for (j = 0; j < p; j++) {
						g = a[j + pm];
						h = a[j + qm];
						a[j + pm] = g - s * (h + g * tau);
						a[j + qm] = h + s * (g - h * tau);
					}
					for (j = p+1, jm = (*m)*(p+1); j < q; j++, jm += (*m) ) {
						g = a[p + jm];
						h = a[j + qm];
						a[p + jm] = g - s * (h + g * tau);
						a[j + qm] = h + s * (g - h * tau);
					}
					for (j = q+1, jm = (*m)*(q+1); j < (*n); j++, jm += (*m) ) {
						g = a[p + jm];
						h = a[q + jm];
						a[p + jm] = g - s * (h + g * tau);
						a[q + jm] = h + s * (g - h * tau);
					}

					for (j = 0; j < (*n); j++) {
						g = v[j + pm];
						h = v[j + qm];
						v[j + pm] = g - s * (h + g * tau);
						v[j + qm] = h + s * (g - h * tau);
					}

					(*nrots)++;
				}
			}
		}
		
		/* End of one sweep of the upper triangle.  */
		
		nsweeps++;

		for (p = 0; p < (*n); p++) {
			b[p] += z[p];	/* Update the b copy of diagonal  */
			d[p] = b[p];	/* Replace d with b to reduce round-off error  */
			z[p] = 0.0;	/* Clear z.  */
		}
	}

	/* Get here via break when converged, or when nsweeps == MAX_SWEEPS.
		Sort eigenvalues by insertion:  */

	for (i = 0; i < (*n)-1; i++) {
		k = i;
		g = d[i];
		for (j = i+1; j < (*n); j++) {  /* Find max location  */
			if (d[j] >= g) {
				k = j;
				g = d[j];
			}
		}
		if (k != i) {  /*  Need to swap value and vector  */
			d[k] = d[i];
			d[i] = g;
			p = i * (*m);
			q = k * (*m);
			for (j = 0; j < (*n); j++) {
				g = v[j + p];
				v[j + p] = v[j + q];
				v[j + q] = g;
			}
		}
	}

	/* Return 0 if converged; else print warning and return -1:  */

	if (nsweeps == MAX_SWEEPS) {
		fprintf (stderr, "GMT_jacobi:  Failed to converge in %d sweeps\n", nsweeps);
		return(-1);
	}
	return(0);
}

int	GMT_jacobi_old (double *a, int *n, int *m, double *d, double *v, double *b, double *z, int *nrots)
/*
 *
 * Find eigenvalues & eigenvectors of a square symmetric matrix by Jacobi's
 * method, which is a convergent series of Givens rotations.
 * Modified from Numerical Recipes FORTRAN edition.
 * Returns integer 0 if OK, -1 if failure to converge in MAX_SWEEPS.
 *
 * programmer:	W. H. F. Smith, 7 June, 1991.
 * Revised:	PW: 12-MAR-1998 for GMT 3.1
 *
 * Caveat Emptor!  Assumes underflows return zero without killing execution.
 * I am not sure what happens if the eigenvalues are degenerate or not distinct.
 */
 

      	    	/* Sent.  n by n matrix in full storage mode.
		On return, superdiagonal elements are destroyed.  */
   	   	/* Sent.  row and column dimension of a as used.  */
   	   	/* Sent.  row and column dimension of a and v as
		allocated, so that a(i,j) is at a[i + (*m)*j].  */
      	    	/* Returned.  vector of n eigenvalues of a.  */
      	    	/* Returned.  n x n matrix of eigenvectors of a,
		with row dimension m  */
      	    	/* Work vector of n elements must be supplied.  */
      	    	/* Another work vector of n elements must be supplied.  */
   	       	/* Returned.  number of Givens rotations performed.  */

{
	int	ip, iq, nsweeps, i, j, k;
	double	sum, threshold, g, h, t, theta, c, s, tau, p;


	/* Begin by initializing v, b, d, and z.  v = identity matrix,
		b = d = diag(a), and z = 0:  */

	for (ip = 0; ip < (*n); ip++) {
		for (iq = 0; iq < (*n); iq++) {
			v[ip + (*m)*iq] = 0.0;
		}
		v[ip + (*m)*ip] = 1.0;
		b[ip] = a[ip + (*m)*ip];
		d[ip] = b[ip];
		z[ip] = 0.0;
	}

	/* End of initializations.  Set counters and begin:  */

	(*nrots) = 0;
	nsweeps = 0;

	while (nsweeps < MAX_SWEEPS) {

		/* Convergence test:
			Sum off-diagonal elements of upper triangle.
			When sum == 0.0 (underflow !) we have converged.
			In this case, break out of while loop.  */

		sum = 0.0;
		for (ip = 0; ip < (*n)-1; ip++) {
			for (iq = ip+1; iq < (*n); iq++) {
				sum += fabs(a[ip + (*m)*iq]);
			}
		}
		if (sum == 0.0) break;

		/* Now we are not converged.
			If (nsweeps < 3) do only the big elements;
				else do them all.  */
		if (nsweeps < 3) {
			threshold = 0.2 * sum / ( (*n) * (*n) );
		}
		else {
			threshold = 0.0;
		}

		/* Now sweep whole upper triangle doing Givens rotations:  */

		for (ip = 0; ip < (*n) - 1; ip++) {
			for (iq = ip+1; iq < (*n); iq++) {

				/* After four sweeps, if the off-diagonal
					element is "small", skip the rotation
					and just set it to zero.  "Small" is
					a relative test by addition:  */

				g = 100.0 * fabs(a[ip + (*m)*iq]);

				if ( (nsweeps > 3) && ( (fabs(d[ip])+g) ==  fabs(d[ip]) ) && ( (fabs(d[iq])+g) ==  fabs(d[iq]) ) ) {
					a[ip + (*m)*iq] = 0.0;
				}
				else if (fabs(a[ip + (*m)*iq]) > threshold) {

					h = d[iq] - d[ip];

					if ( (fabs(h)+g) ==  fabs(h) ) {
						/* I think this could divide by zero if a(i,j) = a(i,i) = a(j,j) = 0.0.
							Would this occur only in a degenerate matrix?  */
						t = a[ip + (*m)*iq] / h;
					}
					else {
						theta = 0.5 * h / a[ip + (*m)*iq];
						t = 1.0 / (fabs(theta) + sqrt(1.0 + theta*theta) );
						if (theta < 0.0) t = -t;
					}

					c = 1.0 / sqrt(1.0 + t*t);
					s = t * c;
					tau = s / (1.0 + c);
					
					h = t * a[ip + (*m)*iq];
					z[ip] -= h;
					z[iq] += h;
					d[ip] -= h;
					d[iq] += h;
					a[ip + (*m)*iq] = 0.0;

					for (j = 0; j < ip; j++) {
						g = a[j + (*m)*ip];
						h = a[j + (*m)*iq];
						a[j + (*m)*ip] = g - s * (h + g * tau);
						a[j + (*m)*iq] = h + s * (g - h * tau);
					}
					for (j = ip+1; j < iq; j++) {
						g = a[ip + (*m)*j];
						h = a[j + (*m)*iq];
						a[ip + (*m)*j] = g - s * (h + g * tau);
						a[j + (*m)*iq] = h + s * (g - h * tau);
					}
					for (j = iq+1; j < (*n); j++) {
						g = a[ip + (*m)*j];
						h = a[iq + (*m)*j];
						a[ip + (*m)*j] = g - s * (h + g * tau);
						a[iq + (*m)*j] = h + s * (g - h * tau);
					}

					for (j = 0; j < (*n); j++) {
						g = v[j + (*m)*ip];
						h = v[j + (*m)*iq];
						v[j + (*m)*ip] = g - s * (h + g * tau);
						v[j + (*m)*iq] = h + s * (g - h * tau);
					}

					(*nrots)++;
				}
			}
		}

		for (ip = 0; ip < (*n); ip++) {
			b[ip] += z[ip];
			d[ip] = b[ip];
			z[ip] = 0.0;
		}

		nsweeps++;
	}

	/* Get here via break when converged, or when nsweeps == MAX_SWEEPS.
		Sort eigenvalues by insertion:  */

	for (i = 0; i < (*n)-1; i++) {
		k = i;
		p = d[i];
		for (j = i+1; j < (*n); j++) {  /* Find max location  */
			if (d[j] >= p) {
				k = j;
				p = d[j];
			}
		}
		if (k != i) {  /*  Need to swap value and vector  */
			d[k] = d[i];
			d[i] = p;
			for (j = 0; j < (*n); j++) {
				p = v[j + (*m)*i];
				v[j + (*m)*i] = v[j + (*m)*k];
				v[j + (*m)*k] = p;
			}
		}
	}

	/* Return 0 if converged; else print warning and return -1:  */

	if (nsweeps == MAX_SWEEPS) {
		fprintf(stderr,"GMT_jacobi:  Failed to converge in %d sweeps\n", nsweeps);
		return(-1);
	}
	return(0);
}

/*  cartesian_stuff.c  --  bits and pieces for doing spherical trig
 *  in terms of dot and cross products.
 *
 * w. h. f. smith, 16 June. 1989
 *
 */

double GMT_dot3v (double *a, double *b)
{
	return (a[0]*b[0] + a[1]*b[1] + a[2]*b[2]);
}

double GMT_mag3v (double *a)
{
	return (d_sqrt(a[0]*a[0] + a[1]*a[1] + a[2]*a[2]));
}

void GMT_normalize3v (double *a)
{
	double r_length;
	r_length = (GMT_mag3v(a));
	if (r_length != 0.0) {
		r_length = 1.0 / r_length;
		a[0] *= r_length;
		a[1] *= r_length;
		a[2] *= r_length;
	}
}

void GMT_cross3v (double *a, double *b, double *c)
{
	c[0] = a[1] * b[2] - a[2] * b[1];
	c[1] = a[2] * b[0] - a[0] * b[2];
	c[2] = a[0] * b[1] - a[1] * b[0];
}

void GMT_geo_to_cart (double *alat, double *alon, double *a, int rads)
{
	/* Convert geographic latitude and longitude (alat, alon)
	   to a 3-vector of unit length (a).  rads = TRUE if we
	   need to convert alat, alon from degrees to radians  */

	double clat, clon, slon;

	if (rads) {
		*alat *= D2R;
		*alon *= D2R;
	}
	sincos (*alat, &a[2], &clat);
	sincos (*alon, &slon, &clon);
	a[0] = clat * clon;
	a[1] = clat * slon;
}

void GMT_cart_to_geo (double *alat, double *alon, double *a, int rads)
{
	/* Convert a 3-vector (a) of unit length into geographic
	   coordinates (alat, alon).  rads = TRUE if we want the
	   lat and lon converted from radians into degrees.  */

	if(rads) {
		*alat = R2D * d_asin(a[2]);
		*alon = R2D * d_atan2(a[1], a[0]);
	}
	else {
		*alat = d_asin(a[2]);
		*alon = d_atan2(a[1],a[0]);
	}
}

int GMT_fix_up_path (double **a_lon, double **a_lat, int n, BOOLEAN greenwich, double step)
                          
      
                  	/* TRUE if we cross Greenwich */
            		/* Add points when step degrees are exceeded */
{
	
	/* Takes pointers to a list of lon/lat pairs and adds auxiliary points if
	 * the great circle distance between two given points exceeds
	 * <step> spherical degree [ 1 degree].
	 */
	 
	int i, j, n_tmp, n_insert = 0, n_alloc;
	double *lon_tmp, *lat_tmp, *old;
	double a[3], b[3], x[3], *lon, *lat;
	double c, d, fraction, theta, i_step;
	
	lon = *a_lon;
	lat = *a_lat;
	
	n_alloc = n;
	lon_tmp = (double *) GMT_memory (VNULL, (size_t)n_alloc, sizeof (double), "GMT_fix_up_path");
	lat_tmp = (double *) GMT_memory (VNULL, (size_t)n_alloc, sizeof (double), "GMT_fix_up_path");
	
	GMT_geo_to_cart (&lat[0], &lon[0], a, TRUE);
	lon_tmp[0] = (lon[0] >= M_PI) ? lon[0] - 2.0*M_PI : lon[0];	lat_tmp[0] = lat[0];
	n_tmp = 1;
	if (step <= 0.0) step = 1.0;
	i_step = 1.0 / step;
	
	for (i = 1; i < n; i++) {
		
		GMT_geo_to_cart (&lat[i],&lon[i], b, TRUE);
		
		if ((theta = d_acos (GMT_dot3v (a, b))) == M_PI) {	/* trouble, no unique great circle */
			fprintf (stderr, "GMT Warning: Two points in input list are antipodal!\n");
		}
		else if ((n_insert = (int)floor (theta * R2D * i_step))) {	/* Must insert n_insert points */
			fraction = step * D2R / theta;
			for (j = 1; j <= n_insert; j++) {
				c = j * fraction;
				d = 1 - c;
				x[0] = a[0] * d + b[0] * c;
				x[1] = a[1] * d + b[1] * c;
				x[2] = a[2] * d + b[2] * c;
				GMT_normalize3v (x);
				GMT_cart_to_geo (&lat_tmp[n_tmp], &lon_tmp[n_tmp], x, FALSE);
				n_tmp++;
				if (n_tmp == n_alloc) {
					n_alloc += GMT_CHUNK;
					lon_tmp = (double *) GMT_memory ((void *) lon_tmp, (size_t)n_alloc, sizeof (double), "GMT_fix_up_path");
					lat_tmp = (double *) GMT_memory ((void *) lat_tmp, (size_t)n_alloc, sizeof (double), "GMT_fix_up_path");
				}
			}
		}
		lon_tmp[n_tmp] = (lon[i] >= M_PI) ? lon[i] - 2.0 * M_PI : lon[i];	lat_tmp[n_tmp] = lat[i];
		n_tmp++;
		if (n_tmp == n_alloc) {
			n_alloc += GMT_CHUNK;
			lon_tmp = (double *) GMT_memory ((void *) lon_tmp, (size_t)n_alloc, sizeof (double), "GMT_fix_up_path");
			lat_tmp = (double *) GMT_memory ((void *) lat_tmp, (size_t)n_alloc, sizeof (double), "GMT_fix_up_path");
		}
		a[0] = b[0];	a[1] = b[1];	a[2] = b[2];
	}
	lon_tmp = (double *) GMT_memory ((void *) lon_tmp, (size_t)n_tmp, sizeof (double), "GMT_fix_up_path");
	lat_tmp = (double *) GMT_memory ((void *) lat_tmp, (size_t)n_tmp, sizeof (double), "GMT_fix_up_path");
	
	old = lon;
	lon = lon_tmp;
	GMT_free ((void *) old);
	old = lat;
	lat = lat_tmp;
	GMT_free ((void *) old);
	for (i = 0; i < n_tmp; i++) {
		lon[i] *= R2D;
		if (!greenwich && lon[i] < 0.0)
			lon[i] += 360.0;
		else if (greenwich && lon[i] > 180.0)
			lon[i] -= 360.0;
		lat[i] *= R2D;
	}
	*a_lon = lon;
	*a_lat = lat;
	return (n_tmp);
}		

int GMT_chol_dcmp (double *a, double *d, double *cond, int nr, int n) {

	/* Given a, a symmetric positive definite matrix
	of size n, and row dimension nr, compute a lower
	triangular matrix b, the Cholesky decomposition 
	of a, so that a = bb'.
	The elements of b over-write the diagonal and sub-
	diagonal elements of a.  The diagonal elements of 
	a are saved in d, and a's super-diagonal elements
	are unchanged, permitting reconstruction of a in
	the event that the algorithm fails.
	Does not do any pivoting or balancing (I wrote it
	for application to Gram matrices, where all the
	diagonal elements of a are the same size.)
	Returns 0 on success, -k on failure, where k is
	the number (in 1 to n) of the point that failed.
	Elements a(i,j) for j < k, and a(k,k) will need
	restoration in this case.
	Success means that the procedure ran to completion
	without a negative square root or a divide by zero.
	It does not guarantee that the system is well-
	conditioned.  The condition number is returned
	in cond as max(b(i,i)) / min(b(i,i)).  Note that
	the condition number of a would be the square of
	this.  This condition number is only set if the
	procedure runs successfully.
	
	W H F Smith, 18 Feb 2000.
*/
	int	i, j, k, ik, ij, kj, kk, nrp1;
	double	eigmax, eigmin;

	nrp1 = nr + 1;
	
	eigmax = eigmin = sqrt ( fabs (a[0]) );

	for (k = 0, kk = 0; k < n; k++, kk+=nrp1 ) {
		d[k] = a[kk];
		for (j = 0, kj = k; j < k; j++, kj += nr) a[kk] -= (a[kj]*a[kj]);
		if (a[kk] <= 0.0) return (-(k+1));
		a[kk] = sqrt(a[kk]);
		if (a[kk] <= 0.0) return (-(k+1));	/* Shouldn't happen ?  */
		
		if (eigmax < a[kk]) eigmax = a[kk];
		if (eigmin > a[kk]) eigmin = a[kk];
		
		for (i = k+1; i < n; i++) {
			ik = i + k*nr;
			for (j = 0, ij = i, kj = k; j < k; j++, ij+=nr, kj+=nr) a[ik] -= (a[ij]*a[kj]);
			a[ik] /= a[kk];
		}
	}
	*cond = eigmax/eigmin;
	return (0);
}

void GMT_chol_recover (double *a, double *d, int nr, int n, int nerr, int donly) {

	/* Given a, a symmetric positive definite matrix of row dimension nr,
	and size n >= abs(nerr), one uses GMT_chol_dcmp() to attempt to find
	b, a lower triangular Cholesky decomposition of a, so that b*b' = a.
	If a is (numerically) not positive definite then GMT_chol_dcmp()
	returns a negative integer nerr, indicating that the diagonal 
	elements of a from a(1,1) to a(-nerr, -nerr) and the sub-diagonal
	elements in columns from 1 to abs(nerr)-1 have been overwritten,
	but the Cholesky decomposition did not run to completion.  A vector
	d has been assigned the original diagonal elements of a from 1 to
	abs(nerr), in this case.
	
	GMT_chol_recover() takes a and d and restores a so that some other
	solution of a may be attempted.  
	
	If (donly != 0) then only the diagonal elements of a will be restored.
	This might be enough if the next attempt will be to run GMT_jacobi()
	on a, for the jacobi routine uses only the upper right triangle of
	a.  If (donly == 0) then all elements of a will be restored, by
	transposing the upper half to the lower half.
	
	To use these routines, the call should be:
	
	if ( (ier = GMT_chol_dcmp (a, d, &cond, nr, n) ) != 0) {
		GMT_chol_recover (a, d, nr, ier, donly);
		[and then solve some other way, e.g. GMT_jacobi]
	}
	else {
		GMT_chol_solv (a, x, y, nr, n);
	}

	W H F Smith, 18 Feb 2000
*/
	
	int	kbad, i, j, ii, ij, ji, nrp1;
	
	kbad = abs(nerr) - 1;
	nrp1 = nr + 1;
	
	for (i = 0, ii = 0; i <=kbad; i++, ii += nrp1) {
		a[ii] = d[i];
	}
	
	if (donly) return;
	
	for (j = 0; j < kbad; j++) {
		for (i = j+1, ij = j*nrp1 + 1, ji = j*nrp1 + nr; i < n; i++, ij++, ji+=nr) {
			a[ij] = a[ji];
		}
	}
	return;
}

void GMT_chol_solv (double *a, double *x, double *y, int nr, int n) {
	/* Given an n by n linear system ax = y, with a a symmetric, 
	positive-definite matrix, y a known vector, and x an unknown
	vector, this routine finds x, if a holds the lower-triangular
	Cholesky factor of a obtained from GMT_chol_dcmp().  nr is the
	row dimension of a.
	The lower triangular Cholesky factor is b such that bb' = a,
	so x is found from y using bt = y, t = b'x, where t is a
	temporary vector.  t is found by forward elimination, and
	then x is found by backward elimination.  t is stored in x
	temporarily.
	This routine does not check the condition number of b.  It
	assumes that GMT_chol_dcmp() ran without error, which means
	that all diagonal elements b[ii] are positive; these are
	divisors in the loops below.
	
	W H F Smith, 18 Feb 2000
*/
	int	i, j, ij, ji, ii, nrp1;
	
	nrp1 = nr + 1;

	/* Find t, store in i, working forward:  */
	for (i = 0, ii = 0; i < n; i++, ii += nrp1) {
		x[i] = y[i];
		for (j = 0, ij = i; j < i; j++, ij += nr) x[i] -= (a[ij] * x[j]);
		x[i] /= a[ii];
	}
	
	/* Find x, starting from t stored in x, going backward:  */
	for (i = n-1, ii = (n-1)*nrp1; i >= 0; i--, ii -= nrp1) {
		for (j = n-1, ji = (n-1)+i*nr; j > i; j--, ji--) x[i] -= (a[ji] * x[j]);
		x[i] /= a[ii];
	}
	return;
}
