changeset 25:6d9e1ee7b35a matthiasm-plugin

* OK, let's revert to a C version (after discovering that the FORTRAN compiler isn't standard on the Mac)
author Chris Cannam
date Thu, 21 Oct 2010 14:38:02 +0100
parents 568ff0daa659
children 906d3705536d
files Makefile.cc-linux nnls.c nnls.f nnls.h
diffstat 4 files changed, 711 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile.cc-linux	Thu Oct 21 12:21:41 2010 +0100
+++ b/Makefile.cc-linux	Thu Oct 21 14:38:02 2010 +0100
@@ -48,6 +48,7 @@
 
 ##  Uncomment these for Linux using the standard tools:
 
+CFLAGS = -I$(VAMP_SDK_DIR) -I$(LAPACK_DIR) -I$(FFT_DIR) -I$(NNLS_DIR) -Wall -fPIC
 CXXFLAGS = -I$(VAMP_SDK_DIR) -I$(LAPACK_DIR) -I$(FFT_DIR) -I$(NNLS_DIR) -Wall -fPIC
 PLUGIN_EXT = .so
 PLUGIN = $(PLUGIN_LIBRARY_NAME)$(PLUGIN_EXT)
@@ -79,9 +80,6 @@
 $(PLUGIN): $(PLUGIN_CODE_OBJECTS)
 	   $(CXX) -o $@ $^ $(LDFLAGS)
 
-nnls.o:	 nnls.f
-	 gfortran -std=legacy -fPIC -Wall -c $< 
-
 clean:
 	rm -f *.o
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nnls.c	Thu Oct 21 14:38:02 2010 +0100
@@ -0,0 +1,705 @@
+
+#include "nnls.h"
+
+typedef int integer;
+typedef unsigned int uinteger;
+typedef char *address;
+typedef short int shortint;
+typedef float real;
+typedef double doublereal;
+
+#define abs(x) ((x) >= 0 ? (x) : -(x))
+#define dabs(x) (doublereal)abs(x)
+#define min(a,b) ((a) <= (b) ? (a) : (b))
+#define max(a,b) ((a) >= (b) ? (a) : (b))
+#define dmin(a,b) (doublereal)min(a,b)
+#define dmax(a,b) (doublereal)max(a,b)
+#define bit_test(a,b)	((a) >> (b) & 1)
+#define bit_clear(a,b)	((a) & ~((uinteger)1 << (b)))
+#define bit_set(a,b)	((a) |  ((uinteger)1 << (b)))
+
+double d_sign(doublereal *a, doublereal *b)
+{
+    double x;
+    x = (*a >= 0 ? *a : - *a);
+    return (*b >= 0 ? x : -x);
+}
+
+/* Table of constant values */
+
+static integer c__1 = 1;
+static integer c__0 = 0;
+static integer c__2 = 2;
+
+doublereal diff_(doublereal *x, doublereal *y)
+{
+    /* System generated locals */
+    doublereal ret_val;
+
+
+/*  Function used in tests that depend on machine precision. */
+
+/*  The original version of this code was developed by */
+/*  Charles L. Lawson and Richard J. Hanson at Jet Propulsion Laboratory */
+/*  1973 JUN 7, and published in the book */
+/*  "SOLVING LEAST SQUARES PROBLEMS", Prentice-HalL, 1974. */
+/*  Revised FEB 1995 to accompany reprinting of the book by SIAM. */
+
+    ret_val = *x - *y;
+    return ret_val;
+} /* diff_ */
+
+/* Subroutine */ int g1_(doublereal *a, doublereal *b, doublereal *cterm, 
+	doublereal *sterm, doublereal *sig)
+{
+    /* System generated locals */
+    doublereal d__1;
+
+    /* Builtin functions */
+    double sqrt(doublereal), d_sign(doublereal *, doublereal *);
+
+    /* Local variables */
+    static doublereal xr, yr;
+
+
+/*     COMPUTE ORTHOGONAL ROTATION MATRIX.. */
+
+/*  The original version of this code was developed by */
+/*  Charles L. Lawson and Richard J. Hanson at Jet Propulsion Laboratory */
+/*  1973 JUN 12, and published in the book */
+/*  "SOLVING LEAST SQUARES PROBLEMS", Prentice-HalL, 1974. */
+/*  Revised FEB 1995 to accompany reprinting of the book by SIAM. */
+
+/*     COMPUTE.. MATRIX   (C, S) SO THAT (C, S)(A) = (SQRT(A**2+B**2)) */
+/*                        (-S,C)         (-S,C)(B)   (   0          ) */
+/*     COMPUTE SIG = SQRT(A**2+B**2) */
+/*        SIG IS COMPUTED LAST TO ALLOW FOR THE POSSIBILITY THAT */
+/*        SIG MAY BE IN THE SAME LOCATION AS A OR B . */
+/*     ------------------------------------------------------------------ */
+/*     ------------------------------------------------------------------ */
+    if (abs(*a) > abs(*b)) {
+	xr = *b / *a;
+/* Computing 2nd power */
+	d__1 = xr;
+	yr = sqrt(d__1 * d__1 + 1.);
+	d__1 = 1. / yr;
+	*cterm = d_sign(&d__1, a);
+	*sterm = *cterm * xr;
+	*sig = abs(*a) * yr;
+	return 0;
+    }
+    if (*b != 0.) {
+	xr = *a / *b;
+/* Computing 2nd power */
+	d__1 = xr;
+	yr = sqrt(d__1 * d__1 + 1.);
+	d__1 = 1. / yr;
+	*sterm = d_sign(&d__1, b);
+	*cterm = *sterm * xr;
+	*sig = abs(*b) * yr;
+	return 0;
+    }
+    *sig = 0.;
+    *cterm = 0.;
+    *sterm = 1.;
+    return 0;
+} /* g1_ */
+
+/*     SUBROUTINE H12 (MODE,LPIVOT,L1,M,U,IUE,UP,C,ICE,ICV,NCV) */
+
+/*  CONSTRUCTION AND/OR APPLICATION OF A SINGLE */
+/*  HOUSEHOLDER TRANSFORMATION..     Q = I + U*(U**T)/B */
+
+/*  The original version of this code was developed by */
+/*  Charles L. Lawson and Richard J. Hanson at Jet Propulsion Laboratory */
+/*  1973 JUN 12, and published in the book */
+/*  "SOLVING LEAST SQUARES PROBLEMS", Prentice-HalL, 1974. */
+/*  Revised FEB 1995 to accompany reprinting of the book by SIAM. */
+/*     ------------------------------------------------------------------ */
+/*                     Subroutine Arguments */
+
+/*     MODE   = 1 OR 2   Selects Algorithm H1 to construct and apply a */
+/*            Householder transformation, or Algorithm H2 to apply a */
+/*            previously constructed transformation. */
+/*     LPIVOT IS THE INDEX OF THE PIVOT ELEMENT. */
+/*     L1,M   IF L1 .LE. M   THE TRANSFORMATION WILL BE CONSTRUCTED TO */
+/*            ZERO ELEMENTS INDEXED FROM L1 THROUGH M.   IF L1 GT. M */
+/*            THE SUBROUTINE DOES AN IDENTITY TRANSFORMATION. */
+/*     U(),IUE,UP    On entry with MODE = 1, U() contains the pivot */
+/*            vector.  IUE is the storage increment between elements. */
+/*            On exit when MODE = 1, U() and UP contain quantities */
+/*            defining the vector U of the Householder transformation. */
+/*            on entry with MODE = 2, U() and UP should contain */
+/*            quantities previously computed with MODE = 1.  These will */
+/*            not be modified during the entry with MODE = 2. */
+/*     C()    ON ENTRY with MODE = 1 or 2, C() CONTAINS A MATRIX WHICH */
+/*            WILL BE REGARDED AS A SET OF VECTORS TO WHICH THE */
+/*            HOUSEHOLDER TRANSFORMATION IS TO BE APPLIED. */
+/*            ON EXIT C() CONTAINS THE SET OF TRANSFORMED VECTORS. */
+/*     ICE    STORAGE INCREMENT BETWEEN ELEMENTS OF VECTORS IN C(). */
+/*     ICV    STORAGE INCREMENT BETWEEN VECTORS IN C(). */
+/*     NCV    NUMBER OF VECTORS IN C() TO BE TRANSFORMED. IF NCV .LE. 0 */
+/*            NO OPERATIONS WILL BE DONE ON C(). */
+/*     ------------------------------------------------------------------ */
+/* Subroutine */ int h12_(integer *mode, integer *lpivot, integer *l1, 
+	integer *m, doublereal *u, integer *iue, doublereal *up, doublereal *
+	c__, integer *ice, integer *icv, integer *ncv)
+{
+    /* System generated locals */
+    integer u_dim1, u_offset, i__1, i__2;
+    doublereal d__1, d__2;
+
+    /* Builtin functions */
+    double sqrt(doublereal);
+
+    /* Local variables */
+    static doublereal b;
+    static integer i__, j, i2, i3, i4;
+    static doublereal cl, sm;
+    static integer incr;
+    static doublereal clinv;
+
+/*     ------------------------------------------------------------------ */
+/*     double precision U(IUE,M) */
+/*     ------------------------------------------------------------------ */
+    /* Parameter adjustments */
+    u_dim1 = *iue;
+    u_offset = 1 + u_dim1;
+    u -= u_offset;
+    --c__;
+
+    /* Function Body */
+    if (0 >= *lpivot || *lpivot >= *l1 || *l1 > *m) {
+	return 0;
+    }
+    cl = (d__1 = u[*lpivot * u_dim1 + 1], abs(d__1));
+    if (*mode == 2) {
+	goto L60;
+    }
+/*                            ****** CONSTRUCT THE TRANSFORMATION. ****** */
+    i__1 = *m;
+    for (j = *l1; j <= i__1; ++j) {
+/* L10: */
+/* Computing MAX */
+	d__2 = (d__1 = u[j * u_dim1 + 1], abs(d__1));
+	cl = max(d__2,cl);
+    }
+    if (cl <= 0.) {
+	goto L130;
+    } else {
+	goto L20;
+    }
+L20:
+    clinv = 1. / cl;
+/* Computing 2nd power */
+    d__1 = u[*lpivot * u_dim1 + 1] * clinv;
+    sm = d__1 * d__1;
+    i__1 = *m;
+    for (j = *l1; j <= i__1; ++j) {
+/* L30: */
+/* Computing 2nd power */
+	d__1 = u[j * u_dim1 + 1] * clinv;
+	sm += d__1 * d__1;
+    }
+    cl *= sqrt(sm);
+    if (u[*lpivot * u_dim1 + 1] <= 0.) {
+	goto L50;
+    } else {
+	goto L40;
+    }
+L40:
+    cl = -cl;
+L50:
+    *up = u[*lpivot * u_dim1 + 1] - cl;
+    u[*lpivot * u_dim1 + 1] = cl;
+    goto L70;
+/*            ****** APPLY THE TRANSFORMATION  I+U*(U**T)/B  TO C. ****** */
+
+L60:
+    if (cl <= 0.) {
+	goto L130;
+    } else {
+	goto L70;
+    }
+L70:
+    if (*ncv <= 0) {
+	return 0;
+    }
+    b = *up * u[*lpivot * u_dim1 + 1];
+/*                       B  MUST BE NONPOSITIVE HERE.  IF B = 0., RETURN. */
+
+    if (b >= 0.) {
+	goto L130;
+    } else {
+	goto L80;
+    }
+L80:
+    b = 1. / b;
+    i2 = 1 - *icv + *ice * (*lpivot - 1);
+    incr = *ice * (*l1 - *lpivot);
+    i__1 = *ncv;
+    for (j = 1; j <= i__1; ++j) {
+	i2 += *icv;
+	i3 = i2 + incr;
+	i4 = i3;
+	sm = c__[i2] * *up;
+	i__2 = *m;
+	for (i__ = *l1; i__ <= i__2; ++i__) {
+	    sm += c__[i3] * u[i__ * u_dim1 + 1];
+/* L90: */
+	    i3 += *ice;
+	}
+	if (sm != 0.) {
+	    goto L100;
+	} else {
+	    goto L120;
+	}
+L100:
+	sm *= b;
+	c__[i2] += sm * *up;
+	i__2 = *m;
+	for (i__ = *l1; i__ <= i__2; ++i__) {
+	    c__[i4] += sm * u[i__ * u_dim1 + 1];
+/* L110: */
+	    i4 += *ice;
+	}
+L120:
+	;
+    }
+L130:
+    return 0;
+} /* h12_ */
+
+/*     SUBROUTINE NNLS  (A,MDA,M,N,B,X,RNORM,W,ZZ,INDEX,MODE) */
+
+/*  Algorithm NNLS: NONNEGATIVE LEAST SQUARES */
+
+/*  The original version of this code was developed by */
+/*  Charles L. Lawson and Richard J. Hanson at Jet Propulsion Laboratory */
+/*  1973 JUN 15, and published in the book */
+/*  "SOLVING LEAST SQUARES PROBLEMS", Prentice-HalL, 1974. */
+/*  Revised FEB 1995 to accompany reprinting of the book by SIAM. */
+
+/*     GIVEN AN M BY N MATRIX, A, AND AN M-VECTOR, B,  COMPUTE AN */
+/*     N-VECTOR, X, THAT SOLVES THE LEAST SQUARES PROBLEM */
+
+/*                      A * X = B  SUBJECT TO X .GE. 0 */
+/*     ------------------------------------------------------------------ */
+/*                     Subroutine Arguments */
+
+/*     A(),MDA,M,N     MDA IS THE FIRST DIMENSIONING PARAMETER FOR THE */
+/*                     ARRAY, A().   ON ENTRY A() CONTAINS THE M BY N */
+/*                     MATRIX, A.           ON EXIT A() CONTAINS */
+/*                     THE PRODUCT MATRIX, Q*A , WHERE Q IS AN */
+/*                     M BY M ORTHOGONAL MATRIX GENERATED IMPLICITLY BY */
+/*                     THIS SUBROUTINE. */
+/*     B()     ON ENTRY B() CONTAINS THE M-VECTOR, B.   ON EXIT B() CON- */
+/*             TAINS Q*B. */
+/*     X()     ON ENTRY X() NEED NOT BE INITIALIZED.  ON EXIT X() WILL */
+/*             CONTAIN THE SOLUTION VECTOR. */
+/*     RNORM   ON EXIT RNORM CONTAINS THE EUCLIDEAN NORM OF THE */
+/*             RESIDUAL VECTOR. */
+/*     W()     AN N-ARRAY OF WORKING SPACE.  ON EXIT W() WILL CONTAIN */
+/*             THE DUAL SOLUTION VECTOR.   W WILL SATISFY W(I) = 0. */
+/*             FOR ALL I IN SET P  AND W(I) .LE. 0. FOR ALL I IN SET Z */
+/*     ZZ()     AN M-ARRAY OF WORKING SPACE. */
+/*     INDEX()     AN INTEGER WORKING ARRAY OF LENGTH AT LEAST N. */
+/*                 ON EXIT THE CONTENTS OF THIS ARRAY DEFINE THE SETS */
+/*                 P AND Z AS FOLLOWS.. */
+
+/*                 INDEX(1)   THRU INDEX(NSETP) = SET P. */
+/*                 INDEX(IZ1) THRU INDEX(IZ2)   = SET Z. */
+/*                 IZ1 = NSETP + 1 = NPP1 */
+/*                 IZ2 = N */
+/*     MODE    THIS IS A SUCCESS-FAILURE FLAG WITH THE FOLLOWING */
+/*             MEANINGS. */
+/*             1     THE SOLUTION HAS BEEN COMPUTED SUCCESSFULLY. */
+/*             2     THE DIMENSIONS OF THE PROBLEM ARE BAD. */
+/*                   EITHER M .LE. 0 OR N .LE. 0. */
+/*             3    ITERATION COUNT EXCEEDED.  MORE THAN 3*N ITERATIONS. */
+
+/*     ------------------------------------------------------------------ */
+/* Subroutine */ int nnls_(doublereal *a, integer *mda, integer *m, integer *
+	n, doublereal *b, doublereal *x, doublereal *rnorm, doublereal *w, 
+	doublereal *zz, integer *index, integer *mode)
+{
+    /* System generated locals */
+    integer a_dim1, a_offset, i__1, i__2;
+    doublereal d__1, d__2;
+
+    /* Builtin functions */
+    double sqrt(doublereal);
+
+    /* Local variables */
+    static integer i__, j, l;
+    static doublereal t;
+    extern /* Subroutine */ int g1_(doublereal *, doublereal *, doublereal *, 
+	    doublereal *, doublereal *);
+    static doublereal cc;
+    extern /* Subroutine */ int h12_(integer *, integer *, integer *, integer 
+	    *, doublereal *, integer *, doublereal *, doublereal *, integer *,
+	     integer *, integer *);
+    static integer ii, jj, ip;
+    static doublereal sm;
+    static integer iz, jz;
+    static doublereal up, ss;
+    static integer iz1, iz2, npp1;
+    extern doublereal diff_(doublereal *, doublereal *);
+    static integer iter;
+    static doublereal temp, wmax, alpha, asave;
+    static integer itmax, izmax, nsetp;
+    static doublereal dummy, unorm, ztest;
+    static integer rtnkey;
+
+/*     ------------------------------------------------------------------ */
+/*     integer INDEX(N) */
+/*     double precision A(MDA,N), B(M), W(N), X(N), ZZ(M) */
+/*     ------------------------------------------------------------------ */
+    /* Parameter adjustments */
+    a_dim1 = *mda;
+    a_offset = 1 + a_dim1;
+    a -= a_offset;
+    --b;
+    --x;
+    --w;
+    --zz;
+    --index;
+
+    /* Function Body */
+    *mode = 1;
+    if (*m <= 0 || *n <= 0) {
+	*mode = 2;
+	return 0;
+    }
+    iter = 0;
+    itmax = *n * 3;
+
+/*                    INITIALIZE THE ARRAYS INDEX() AND X(). */
+
+    i__1 = *n;
+    for (i__ = 1; i__ <= i__1; ++i__) {
+	x[i__] = 0.;
+/* L20: */
+	index[i__] = i__;
+    }
+
+    iz2 = *n;
+    iz1 = 1;
+    nsetp = 0;
+    npp1 = 1;
+/*                             ******  MAIN LOOP BEGINS HERE  ****** */
+L30:
+/*                  QUIT IF ALL COEFFICIENTS ARE ALREADY IN THE SOLUTION. */
+/*                        OR IF M COLS OF A HAVE BEEN TRIANGULARIZED. */
+
+    if (iz1 > iz2 || nsetp >= *m) {
+	goto L350;
+    }
+
+/*         COMPUTE COMPONENTS OF THE DUAL (NEGATIVE GRADIENT) VECTOR W(). */
+
+    i__1 = iz2;
+    for (iz = iz1; iz <= i__1; ++iz) {
+	j = index[iz];
+	sm = 0.;
+	i__2 = *m;
+	for (l = npp1; l <= i__2; ++l) {
+/* L40: */
+	    sm += a[l + j * a_dim1] * b[l];
+	}
+	w[j] = sm;
+/* L50: */
+    }
+/*                                   FIND LARGEST POSITIVE W(J). */
+L60:
+    wmax = 0.;
+    i__1 = iz2;
+    for (iz = iz1; iz <= i__1; ++iz) {
+	j = index[iz];
+	if (w[j] > wmax) {
+	    wmax = w[j];
+	    izmax = iz;
+	}
+/* L70: */
+    }
+
+/*             IF WMAX .LE. 0. GO TO TERMINATION. */
+/*             THIS INDICATES SATISFACTION OF THE KUHN-TUCKER CONDITIONS. */
+
+    if (wmax <= 0.) {
+	goto L350;
+    }
+    iz = izmax;
+    j = index[iz];
+
+/*     THE SIGN OF W(J) IS OK FOR J TO BE MOVED TO SET P. */
+/*     BEGIN THE TRANSFORMATION AND CHECK NEW DIAGONAL ELEMENT TO AVOID */
+/*     NEAR LINEAR DEPENDENCE. */
+
+    asave = a[npp1 + j * a_dim1];
+    i__1 = npp1 + 1;
+    h12_(&c__1, &npp1, &i__1, m, &a[j * a_dim1 + 1], &c__1, &up, &dummy, &
+	    c__1, &c__1, &c__0);
+    unorm = 0.;
+    if (nsetp != 0) {
+	i__1 = nsetp;
+	for (l = 1; l <= i__1; ++l) {
+/* L90: */
+/* Computing 2nd power */
+	    d__1 = a[l + j * a_dim1];
+	    unorm += d__1 * d__1;
+	}
+    }
+    unorm = sqrt(unorm);
+    d__2 = unorm + (d__1 = a[npp1 + j * a_dim1], abs(d__1)) * .01;
+    if (diff_(&d__2, &unorm) > 0.) {
+
+/*        COL J IS SUFFICIENTLY INDEPENDENT.  COPY B INTO ZZ, UPDATE ZZ */
+/*        AND SOLVE FOR ZTEST ( = PROPOSED NEW VALUE FOR X(J) ). */
+
+	i__1 = *m;
+	for (l = 1; l <= i__1; ++l) {
+/* L120: */
+	    zz[l] = b[l];
+	}
+	i__1 = npp1 + 1;
+	h12_(&c__2, &npp1, &i__1, m, &a[j * a_dim1 + 1], &c__1, &up, &zz[1], &
+		c__1, &c__1, &c__1);
+	ztest = zz[npp1] / a[npp1 + j * a_dim1];
+
+/*                                     SEE IF ZTEST IS POSITIVE */
+
+	if (ztest > 0.) {
+	    goto L140;
+	}
+    }
+
+/*     REJECT J AS A CANDIDATE TO BE MOVED FROM SET Z TO SET P. */
+/*     RESTORE A(NPP1,J), SET W(J)=0., AND LOOP BACK TO TEST DUAL */
+/*     COEFFS AGAIN. */
+
+    a[npp1 + j * a_dim1] = asave;
+    w[j] = 0.;
+    goto L60;
+
+/*     THE INDEX  J=INDEX(IZ)  HAS BEEN SELECTED TO BE MOVED FROM */
+/*     SET Z TO SET P.    UPDATE B,  UPDATE INDICES,  APPLY HOUSEHOLDER */
+/*     TRANSFORMATIONS TO COLS IN NEW SET Z,  ZERO SUBDIAGONAL ELTS IN */
+/*     COL J,  SET W(J)=0. */
+
+L140:
+    i__1 = *m;
+    for (l = 1; l <= i__1; ++l) {
+/* L150: */
+	b[l] = zz[l];
+    }
+
+    index[iz] = index[iz1];
+    index[iz1] = j;
+    ++iz1;
+    nsetp = npp1;
+    ++npp1;
+
+    if (iz1 <= iz2) {
+	i__1 = iz2;
+	for (jz = iz1; jz <= i__1; ++jz) {
+	    jj = index[jz];
+	    h12_(&c__2, &nsetp, &npp1, m, &a[j * a_dim1 + 1], &c__1, &up, &a[
+		    jj * a_dim1 + 1], &c__1, mda, &c__1);
+/* L160: */
+	}
+    }
+
+    if (nsetp != *m) {
+	i__1 = *m;
+	for (l = npp1; l <= i__1; ++l) {
+/* L180: */
+	    a[l + j * a_dim1] = 0.;
+	}
+    }
+
+    w[j] = 0.;
+/*                                SOLVE THE TRIANGULAR SYSTEM. */
+/*                                STORE THE SOLUTION TEMPORARILY IN ZZ(). */
+    rtnkey = 1;
+    goto L400;
+L200:
+
+/*                       ******  SECONDARY LOOP BEGINS HERE ****** */
+
+/*                          ITERATION COUNTER. */
+
+L210:
+    ++iter;
+    if (iter > itmax) {
+	*mode = 3;
+/*         write (*,'(/a)') ' NNLS quitting on iteration count.' */
+	goto L350;
+    }
+
+/*                    SEE IF ALL NEW CONSTRAINED COEFFS ARE FEASIBLE. */
+/*                                  IF NOT COMPUTE ALPHA. */
+
+    alpha = 2.;
+    i__1 = nsetp;
+    for (ip = 1; ip <= i__1; ++ip) {
+	l = index[ip];
+	if (zz[ip] <= 0.) {
+	    t = -x[l] / (zz[ip] - x[l]);
+	    if (alpha > t) {
+		alpha = t;
+		jj = ip;
+	    }
+	}
+/* L240: */
+    }
+
+/*          IF ALL NEW CONSTRAINED COEFFS ARE FEASIBLE THEN ALPHA WILL */
+/*          STILL = 2.    IF SO EXIT FROM SECONDARY LOOP TO MAIN LOOP. */
+
+    if (alpha == 2.) {
+	goto L330;
+    }
+
+/*          OTHERWISE USE ALPHA WHICH WILL BE BETWEEN 0. AND 1. TO */
+/*          INTERPOLATE BETWEEN THE OLD X AND THE NEW ZZ. */
+
+    i__1 = nsetp;
+    for (ip = 1; ip <= i__1; ++ip) {
+	l = index[ip];
+	x[l] += alpha * (zz[ip] - x[l]);
+/* L250: */
+    }
+
+/*        MODIFY A AND B AND THE INDEX ARRAYS TO MOVE COEFFICIENT I */
+/*        FROM SET P TO SET Z. */
+
+    i__ = index[jj];
+L260:
+    x[i__] = 0.;
+
+    if (jj != nsetp) {
+	++jj;
+	i__1 = nsetp;
+	for (j = jj; j <= i__1; ++j) {
+	    ii = index[j];
+	    index[j - 1] = ii;
+	    g1_(&a[j - 1 + ii * a_dim1], &a[j + ii * a_dim1], &cc, &ss, &a[j 
+		    - 1 + ii * a_dim1]);
+	    a[j + ii * a_dim1] = 0.;
+	    i__2 = *n;
+	    for (l = 1; l <= i__2; ++l) {
+		if (l != ii) {
+
+/*                 Apply procedure G2 (CC,SS,A(J-1,L),A(J,L)) */
+
+		    temp = a[j - 1 + l * a_dim1];
+		    a[j - 1 + l * a_dim1] = cc * temp + ss * a[j + l * a_dim1]
+			    ;
+		    a[j + l * a_dim1] = -ss * temp + cc * a[j + l * a_dim1];
+		}
+/* L270: */
+	    }
+
+/*                 Apply procedure G2 (CC,SS,B(J-1),B(J)) */
+
+	    temp = b[j - 1];
+	    b[j - 1] = cc * temp + ss * b[j];
+	    b[j] = -ss * temp + cc * b[j];
+/* L280: */
+	}
+    }
+
+    npp1 = nsetp;
+    --nsetp;
+    --iz1;
+    index[iz1] = i__;
+
+/*        SEE IF THE REMAINING COEFFS IN SET P ARE FEASIBLE.  THEY SHOULD */
+/*        BE BECAUSE OF THE WAY ALPHA WAS DETERMINED. */
+/*        IF ANY ARE INFEASIBLE IT IS DUE TO ROUND-OFF ERROR.  ANY */
+/*        THAT ARE NONPOSITIVE WILL BE SET TO ZERO */
+/*        AND MOVED FROM SET P TO SET Z. */
+
+    i__1 = nsetp;
+    for (jj = 1; jj <= i__1; ++jj) {
+	i__ = index[jj];
+	if (x[i__] <= 0.) {
+	    goto L260;
+	}
+/* L300: */
+    }
+
+/*         COPY B( ) INTO ZZ( ).  THEN SOLVE AGAIN AND LOOP BACK. */
+
+    i__1 = *m;
+    for (i__ = 1; i__ <= i__1; ++i__) {
+/* L310: */
+	zz[i__] = b[i__];
+    }
+    rtnkey = 2;
+    goto L400;
+L320:
+    goto L210;
+/*                      ******  END OF SECONDARY LOOP  ****** */
+
+L330:
+    i__1 = nsetp;
+    for (ip = 1; ip <= i__1; ++ip) {
+	i__ = index[ip];
+/* L340: */
+	x[i__] = zz[ip];
+    }
+/*        ALL NEW COEFFS ARE POSITIVE.  LOOP BACK TO BEGINNING. */
+    goto L30;
+
+/*                        ******  END OF MAIN LOOP  ****** */
+
+/*                        COME TO HERE FOR TERMINATION. */
+/*                     COMPUTE THE NORM OF THE FINAL RESIDUAL VECTOR. */
+
+L350:
+    sm = 0.;
+    if (npp1 <= *m) {
+	i__1 = *m;
+	for (i__ = npp1; i__ <= i__1; ++i__) {
+/* L360: */
+/* Computing 2nd power */
+	    d__1 = b[i__];
+	    sm += d__1 * d__1;
+	}
+    } else {
+	i__1 = *n;
+	for (j = 1; j <= i__1; ++j) {
+/* L380: */
+	    w[j] = 0.;
+	}
+    }
+    *rnorm = sqrt(sm);
+    return 0;
+
+/*     THE FOLLOWING BLOCK OF CODE IS USED AS AN INTERNAL SUBROUTINE */
+/*     TO SOLVE THE TRIANGULAR SYSTEM, PUTTING THE SOLUTION IN ZZ(). */
+
+L400:
+    i__1 = nsetp;
+    for (l = 1; l <= i__1; ++l) {
+	ip = nsetp + 1 - l;
+	if (l != 1) {
+	    i__2 = ip;
+	    for (ii = 1; ii <= i__2; ++ii) {
+		zz[ii] -= a[ii + jj * a_dim1] * zz[ip + 1];
+/* L410: */
+	    }
+	}
+	jj = index[ip];
+	zz[ip] /= a[ip + jj * a_dim1];
+/* L430: */
+    }
+    switch (rtnkey) {
+	case 1:  goto L200;
+	case 2:  goto L320;
+    }
+    return 0;
+} /* nnls_ */
+
--- a/nnls.f	Thu Oct 21 12:21:41 2010 +0100
+++ b/nnls.f	Thu Oct 21 14:38:02 2010 +0100
@@ -345,7 +345,7 @@
       ITER=ITER+1   
       IF (ITER .gt. ITMAX) then
          MODE=3
-         write (*,'(/a)') ' NNLS quitting on iteration count.'
+c         write (*,'(/a)') ' NNLS quitting on iteration count.'
          GO TO 350 
       endif
 C   
--- a/nnls.h	Thu Oct 21 12:21:41 2010 +0100
+++ b/nnls.h	Thu Oct 21 14:38:02 2010 +0100
@@ -1,7 +1,9 @@
 #ifndef NNLS_H
 #define NNLS_H
 
+#ifdef __cplusplus
 extern "C" {
+#endif
 
 int nnls_(double *a, int *mda, int *m, int *n, 
 	  double *b, double *x, double *rnorm, 
@@ -9,7 +11,9 @@
 
 #define NNLS nnls_
 
+#ifdef __cplusplus
 }
+#endif
 
 #endif