/* * nnls.c (c) 2003-2009 Turku PET Centre * This file contains the routine NNLS (nonnegative least squares) * and the subroutines required by it, except h12, which is in * file 'lss_h12.c'. * * This routine is based on the text and fortran code in * C.L. Lawson and R.J. Hanson, Solving Least Squares Problems, * Prentice-Hall, Englewood Cliffs, New Jersey, 1974. * Version: * 2002-08-19 Vesa Oikonen * 2003-05-08 Kaisa Sederholm & VO * Included function nnlsWght(). * 2003-05-12 KS * Variable a_dim1 excluded * * Usage of the coefficient matrix altered so that it is * given in a[][] instead of a[]. * 2003-11-06 VO * If n<2, then itmax is set to n*n instead of previous n*3. * 2004-09-17 VO * Doxygen style comments. * 2006-24-04 Pauli Sundberg * Added some debuging output, and made some comments more precise. * 2007-05-17 VO * 2009-04-16 VO * Corrected a bug in nnls() which may have caused an infinite loop. * 009-04-27 VO * Added function nnlsWghtSquared() for faster pixel-by-pixel calculations. * Checking for exceeding iteration count is corrected in nnls(). */ #include #include #include #include #include #define MAX(a,b) ((a) >= (b) ? (a) : (b)) #define ABS(x) ((x) >= 0 ? (x) : -(x)) int64_t h12( int64_t mode, int64_t lpivot, int64_t l1, int64_t m, double *u, int64_t u_dim1, double *up, double *cm, int64_t ice, int64_t icv, int64_t ncv) { double d1, b, clinv, cl, sm; int64_t k, j; /* Check parameters */ if (mode!=1 && mode!=2) return(1); if (m<1 || u==NULL || u_dim1<1 || cm==NULL) assert(0); // return(1); if (lpivot<0 || lpivot>=l1 || l1>m) // assert(0); return(1); /* Function Body */ cl = ABS( u[lpivot*u_dim1] ); // cl= (d1 = u[lpivot*u_dim1], fabs(d1)); if (mode==2) { /* Apply transformation I+U*(U**T)/B to cm[] */ if(cl<=0.) // assert(0); return(0); } else { /* Construct the transformation */ /* This is the way provided in the original pseudocode sm = 0; for (j = l1; j < m; j++) { d1 = u[j * u_dim1]; sm += d1*d1; } d1 = u[lpivot * u_dim1]; sm += d1*d1; sm = sqrt(sm); if (u[lpivot*u_dim1] > 0) sm=-sm; up[0] = u[lpivot*u_dim1] - sm; u[lpivot*u_dim1]=sm; printf("Got sum: %f\n",sm); */ /* and this trying to compensate overflow */ for (j=l1; j 0.) cl=-cl; up[0] = u[lpivot*u_dim1] - cl; u[lpivot*u_dim1]=cl; } // no vectors where to apply? only change pivot vector! b=up[0] * u[lpivot*u_dim1]; /* b must be nonpositive here; if b>=0., then return */ if (b == 0) return(0); // ok, for all vectors we want to apply for (j =0; j < ncv; j++) { sm = cm[ lpivot * ice + j * icv ] * (up[0]); for (k=l1; k fabs(b) ) { xr = b / a; d1 = xr; yr = sqrt(d1*d1 + 1.); d1 = 1./yr; *cterm=(a>=0.0 ? fabs(d1) : -fabs(d1)); *sterm=(*cterm)*xr; *sig=fabs(a)*yr; } else if( b != 0.) { xr = a / b; d1 = xr; yr = sqrt(d1 * d1 + 1.); d1 = 1. / yr; *sterm=(b>=0.0 ? fabs(d1) : -fabs(d1)); *cterm=(*sterm)*xr; *sig=fabs(b)*yr; } else { *sig=0.; *cterm=0.; *sterm=1.; } } int64_t nnls_algorithm(double *a, int64_t m,int64_t n, double *b, double *x, double *rnorm) { int64_t pfeas; int ret=0; int64_t iz; int64_t jz; int64_t k, j=0, l, itmax, izmax=0, ii, jj=0, ip; double d1, d2, sm, up, ss; double temp, wmax, t, alpha, asave, dummy, unorm, ztest, cc; /* Check the parameters and data */ if(m <= 0 || n <= 0 || a == NULL || b == NULL || x == NULL) return(2); /* Allocate memory for working space, if required */ double *w = calloc(n, sizeof(double)); double *zz = calloc(m, sizeof(double)); int64_t *index = calloc(n, sizeof(int64_t)); if(w == NULL || zz == NULL || index == NULL) return(2); /* Initialize the arrays INDEX[] and X[] */ for(k=0; kwmax) {wmax=w[j]; izmax=iz;}} /* Terminate if wmax<=0.; */ /* it indicates satisfaction of the Kuhn-Tucker conditions */ if(wmax<=0.0) break; 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[j*m + npp1]; h12(1, npp1, npp1+1, m, &a[j*m +0], 1, &up, &dummy, 1, 1, 0); unorm=0.; if(nsetp!=0){ for(l=0; l0.) { /* Col j is sufficiently independent. Copy B into ZZ, update ZZ */ /* and solve for ztest ( = proposed new value for X[j] ) */ for(l=0; l0.) break; } /* 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[j*m+ npp1]=asave; w[j]=0.; } /* while(1) */ if(wmax<=0.0) break; /* Index j=INDEX[iz] has been selected to be moved from set Z to set P. */ /* Update B and indices, apply householder transformations to cols in */ /* new set Z, zero subdiagonal elts in col j, set W[j]=0. */ for(l=0; l t) { alpha = t; jj = ip - 1; } } } /* If all new constrained coeffs are feasible then still alpha==2. */ /* If so, then exit from the secondary loop to main loop */ if(alpha==2.0) break; /* Use alpha (0.=itmax) { ret = 1; break; } for(ip=0; ip