changeset 5:ec9fcfe1ce9e matthiasm-plugin

dont know what I did here, thought it nnls.cc had not been there
author matthiasm
date Tue, 01 Jun 2010 12:02:58 +0000
parents 266d23a41cdc
children a5302cf1cdb3
files nnls.cc
diffstat 1 files changed, 614 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nnls.cc	Tue Jun 01 12:02:58 2010 +0000
@@ -0,0 +1,614 @@
+// 	$Id: nnls.cc,v 1.1.2.1 2003/03/06 16:28:07 suvrit Exp $	
+// File: nnls.cc
+// Implements the Lawson-Hanson NNLS algorithm
+// Copied over from nnls.c so i don't ahve copyright on this
+//...somebody else has.....don't know if this should be under GPL or LGPL or
+// whatever, but i'll put a lil note here anyways:
+
+// Copyright (C) 2004 Lawson-Hanson
+// Modifications to adapt to c++ by Suvrit Sra.
+
+// 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, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+
+#include "nnls.h"
+
+float d_sign(float& a, float& b)
+{
+  float x;
+  x = (a >= 0 ? a : - a);
+  return (b >= 0 ? x : -x);
+}
+ 
+/* Table of constant values */
+ 
+int c__1 = 1;
+int c__0 = 0;
+int c__2 = 2;
+
+
+int nnls(float* a,  int mda,  int m,  int n, float* b, 
+	 float* x, float* rnorm, float* w, float* zz, int* index, 
+	 int* mode)
+{
+  /* System generated locals */
+  int a_dim1, a_offset, idx1, idx2;
+  float d1, d2;
+ 
+ 
+  /* Local variables */
+  static int iter;
+  static float temp, wmax;
+  static int i__, j, l;
+  static float t, alpha, asave;
+  static int itmax, izmax, nsetp;
+  static float unorm, ztest, cc;
+  float dummy[2];
+  static int ii, jj, ip;
+  static float sm;
+  static int iz, jz;
+  static float up, ss;
+  static int rtnkey, iz1, iz2, npp1;
+ 
+  /*     ------------------------------------------------------------------ 
+   */
+  /*     int INDEX(N) */
+  /*     float precision A(MDA,N), B(M), W(N), X(N), ZZ(M) */
+  /*     ------------------------------------------------------------------ 
+   */
+  /* Parameter adjustments */
+  a_dim1 = mda;
+  a_offset = a_dim1 + 1;
+  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(). */
+ 
+  idx1 = n;
+  for (i__ = 1; i__ <= idx1; ++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(). 
+   */
+ 
+  idx1 = iz2;
+  for (iz = iz1; iz <= idx1; ++iz) {
+    j = index[iz];
+    sm = 0.;
+    idx2 = m;
+    for (l = npp1; l <= idx2; ++l) {
+      /* L40: */
+      sm += a[l + j * a_dim1] * b[l];
+    }
+    w[j] = sm;
+    /* L50: */
+  }
+  /*                                   FIND LARGEST POSITIVE W(J). */
+ L60:
+  wmax = 0.;
+  idx1 = iz2;
+  for (iz = iz1; iz <= idx1; ++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];
+  idx1 = npp1 + 1;
+  h12(c__1, &npp1, &idx1, m, &a[j * a_dim1 + 1], &c__1, &up, dummy, &
+      c__1, &c__1, &c__0);
+  unorm = 0.;
+  if (nsetp != 0) {
+    idx1 = nsetp;
+    for (l = 1; l <= idx1; ++l) {
+      /* L90: */
+      /* Computing 2nd power */
+      d1 = a[l + j * a_dim1];
+      unorm += d1 * d1;
+    }
+  }
+  unorm = sqrt(unorm);
+  d2 = unorm + (d1 = a[npp1 + j * a_dim1], nnls_abs(d1)) * .01;
+  if ((d2- unorm) > 0.) {
+ 
+    /*        COL J IS SUFFICIENTLY INDEPENDENT.  COPY B INTO ZZ, UPDATE Z
+	      Z */
+    /*        AND SOLVE FOR ZTEST ( = PROPOSED NEW VALUE FOR X(J) ). */
+ 
+    idx1 = m;
+    for (l = 1; l <= idx1; ++l) {
+      /* L120: */
+      zz[l] = b[l];
+    }
+    idx1 = npp1 + 1;
+    h12(c__2, &npp1, &idx1, 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:
+  idx1 = m;
+  for (l = 1; l <= idx1; ++l) {
+    /* L150: */
+    b[l] = zz[l];
+  }
+ 
+  index[iz] = index[iz1];
+  index[iz1] = j;
+  ++iz1;
+  nsetp = npp1;
+  ++npp1;
+ 
+  if (iz1 <= iz2) {
+    idx1 = iz2;
+    for (jz = iz1; jz <= idx1; ++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) {
+    idx1 = m;
+    for (l = npp1; l <= idx1; ++l) {
+      /* L180: */
+      // SS: CHECK THIS DAMAGE....
+      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;
+    /* The following lines were replaced after the f2c translation */
+    /* s_wsfe(&io___22); */
+    /* do_fio(&c__1, " NNLS quitting on iteration count.", 34L); */
+    /* e_wsfe(); */
+    fprintf(stdout, "\n NNLS quitting on iteration count.\n");
+    fflush(stdout);
+    goto L350;
+  }
+ 
+  /*                    SEE IF ALL NEW CONSTRAINED COEFFS ARE FEASIBLE. */
+  /*                                  IF NOT COMPUTE ALPHA. */
+ 
+  alpha = 2.;
+  idx1 = nsetp;
+  for (ip = 1; ip <= idx1; ++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. */
+ 
+  idx1 = nsetp;
+  for (ip = 1; ip <= idx1; ++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;
+    idx1 = nsetp;
+    for (j = jj; j <= idx1; ++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]);
+      // SS: CHECK THIS DAMAGE...
+      a[j + ii * a_dim1] = 0.;
+      idx2 = n;
+      for (l = 1; l <= idx2; ++l) {
+	if (l != ii) {
+ 
+	  /*                 Apply procedure G2 (CC,SS,A(J-1,L),A(J,
+			     L)) */
+ 
+	  temp = a[j - 1 + l * a_dim1];
+	  // SS: CHECK THIS DAMAGE
+	  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. */
+ 
+  idx1 = nsetp;
+  for (jj = 1; jj <= idx1; ++jj) {
+    i__ = index[jj];
+    if (x[i__] <= 0.) {
+      goto L260;
+    }
+    /* L300: */
+  }
+ 
+  /*         COPY B( ) INTO ZZ( ).  THEN SOLVE AGAIN AND LOOP BACK. */
+ 
+  idx1 = m;
+  for (i__ = 1; i__ <= idx1; ++i__) {
+    /* L310: */
+    zz[i__] = b[i__];
+  }
+  rtnkey = 2;
+  goto L400;
+ L320:
+  goto L210;
+  /*                      ******  END OF SECONDARY LOOP  ****** */
+ 
+ L330:
+  idx1 = nsetp;
+  for (ip = 1; ip <= idx1; ++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) {
+    idx1 = m;
+    for (i__ = npp1; i__ <= idx1; ++i__) {
+      /* L360: */
+      /* Computing 2nd power */
+      d1 = b[i__];
+      sm += d1 * d1;
+    }
+  } else {
+    idx1 = n;
+    for (j = 1; j <= idx1; ++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:
+  idx1 = nsetp;
+  for (l = 1; l <= idx1; ++l) {
+    ip = nsetp + 1 - l;
+    if (l != 1) {
+      idx2 = ip;
+      for (ii = 1; ii <= idx2; ++ii) {
+	zz[ii] -= a[ii + jj * a_dim1] * zz[ip + 1];
+	/* L410: */
+      }
+    }
+    jj = index[ip];
+    zz[ip] /= a[ip + jj * a_dim1];
+    /* L430: */
+  }
+  switch ((int)rtnkey) {
+  case 1:  goto L200;
+  case 2:  goto L320;
+  }
+ 
+  /* The next line was added after the f2c translation to keep
+     compilers from complaining about a void return from a non-void
+     function. */
+  return 0;
+ 
+} /* nnls_ */
+
+
+int g1(float* a, float* b, float* cterm, float* sterm, float* sig)
+{
+  /* System generated locals */
+  float d;
+ 
+  static float xr, yr;
+ 
+ 
+  if (nnls_abs(*a) > nnls_abs(*b)) {
+    xr = *b / *a;
+    /* Computing 2nd power */
+    d = xr;
+    yr = sqrt(d * d + 1.);
+    d = 1. / yr;
+    *cterm = d_sign(d, *a);
+    *sterm = *cterm * xr;
+    *sig = nnls_abs(*a) * yr;
+    return 0;
+  }
+  if (*b != 0.) {
+    xr = *a / *b;
+    /* Computing 2nd power */
+    d = xr;
+    yr = sqrt(d * d + 1.);
+    d = 1. / yr;
+    *sterm = d_sign(d, *b);
+    *cterm = *sterm * xr;
+    *sig = nnls_abs(*b) * yr;
+    return 0;
+  }
+  *sig = 0.;
+  *cterm = 0.;
+  *sterm = 1.;
+  return 0;
+} /* g1_ */
+ 
+
+/* See nnls.h for explanation */
+int h12(int mode, int* lpivot, int* l1, 
+	int m, float* u, int* iue, float* up, float* c__, 
+	int* ice, int* icv, int* ncv)
+{
+  /* System generated locals */
+  int u_dim1, u_offset, idx1, idx2;
+  float d, d2;
+ 
+  /* Builtin functions */
+  /* The following line was commented out after the f2c translation */
+  /* float sqrt(); */
+ 
+  /* Local variables */
+  static int incr;
+  static float b;
+  static int i__, j;
+  static float clinv;
+  static int i2, i3, i4;
+  static float cl, sm;
+ 
+  /*     ------------------------------------------------------------------ 
+   */
+  /*     float precision U(IUE,M) */
+  /*     ------------------------------------------------------------------ 
+   */
+  /* Parameter adjustments */
+  u_dim1 = *iue;
+  u_offset = u_dim1 + 1;
+  u -= u_offset;
+  --c__;
+ 
+  /* Function Body */
+  if (0 >= *lpivot || *lpivot >= *l1 || *l1 > m) {
+    return 0;
+  }
+  cl = (d = u[*lpivot * u_dim1 + 1], nnls_abs(d));
+  if (mode == 2) {
+    goto L60;
+  }
+  /*                            ****** CONSTRUCT THE TRANSFORMATION. ****** 
+   */
+  idx1 = m;
+  for (j = *l1; j <= idx1; ++j) {
+    /* L10: */
+    /* Computing MAX */
+    d2 = (d = u[j * u_dim1 + 1], nnls_abs(d));
+    cl = nnls_max(d2,cl);
+  }
+  if (cl <= 0.) {
+    goto L130;
+  } else {
+    goto L20;
+  }
+ L20:
+  clinv = 1. / cl;
+  /* Computing 2nd power */
+  d = u[*lpivot * u_dim1 + 1] * clinv;
+  sm = d * d;
+  idx1 = m;
+  for (j = *l1; j <= idx1; ++j) {
+    /* L30: */
+    /* Computing 2nd power */
+    d = u[j * u_dim1 + 1] * clinv;
+    sm += d * d;
+  }
+  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);
+  idx1 = *ncv;
+  for (j = 1; j <= idx1; ++j) {
+    i2 += *icv;
+    i3 = i2 + incr;
+    i4 = i3;
+    sm = c__[i2] * *up;
+    idx2 = m;
+    for (i__ = *l1; i__ <= idx2; ++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;
+    idx2 = m;
+    for (i__ = *l1; i__ <= idx2; ++i__) {
+      c__[i4] += sm * u[i__ * u_dim1 + 1];
+      /* L110: */
+      i4 += *ice;
+    }
+  L120:
+    ;
+  }
+ L130:
+  return 0;
+} /* h12 */
+ 
+