TPCCLIB
Loading...
Searching...
No Matches
nnls.c
Go to the documentation of this file.
1
9/*****************************************************************************/
10#include "tpcclibConfig.h"
11/*****************************************************************************/
12#include <stdio.h>
13#include <stdlib.h>
14#include <math.h>
15/*****************************************************************************/
16#include "tpcextensions.h"
17/*****************************************************************************/
18#include "tpclinopt.h"
19/*****************************************************************************/
20
21/*****************************************************************************/
23/* Local function definitions */
24int nnls_lss_h12(int mode, int lpivot, int l1, int m, double *u, double *up, double *cm);
25void nnls_lss_g1(double a, double b, double *cterm, double *sterm, double *sig);
27/*****************************************************************************/
28
29/*****************************************************************************/
43int nnls(
47 double **a,
49 int m,
51 int n,
54 double *b,
56 double *x,
59 double *rnorm,
64 double *wp,
67 double *zzp,
70 int *indexp
71) {
72 /* Check the parameters and data */
73 if(m<=0 || n<=0 || a==NULL || b==NULL || x==NULL) return(2);
74 if(rnorm!=NULL) *rnorm=nan("");
75 /* Allocate memory for working space, if required */
76 int *index=NULL;
77 double *w=NULL, *zz=NULL;
78 if(wp!=NULL) w=wp; else w=(double*)calloc(n, sizeof(double));
79 if(zzp!=NULL) zz=zzp; else zz=(double*)calloc(m, sizeof(double));
80 if(indexp!=NULL) index=indexp; else index=(int*)calloc(n, sizeof(int));
81 if(w==NULL || zz==NULL || index==NULL) return(2);
82
83 /* Initialize the arrays INDEX[] and X[] */
84 for(int ni=0; ni<n; ni++) {x[ni]=0.; index[ni]=ni;}
85 int iz1=0;
86 int iz2=n-1;
87 int nsetp=0;
88 int npp1=0;
89
90 /* Main loop; quit if all coefficients are already in the solution or
91 if M cols of A have been triangulated */
92 double up=0.0;
93 int itmax; if(n<3) itmax=n*3; else itmax=n*n;
94 int iter=0;
95 int k, j=0, jj=0;
96 while(iz1<=iz2 && nsetp<m) {
97 /* Compute components of the dual (negative gradient) vector W[] */
98 for(int iz=iz1; iz<=iz2; iz++) {
99 int ni=index[iz];
100 double sm=0.;
101 for(int mi=npp1; mi<m; mi++) sm+=a[ni][mi]*b[mi];
102 w[ni]=sm;
103 }
104
105 double wmax;
106 int izmax=0;
107 while(1) {
108
109 /* Find largest positive W[j] */
110 wmax=0.0;
111 for(int iz=iz1; iz<=iz2; iz++) {
112 int i=index[iz];
113 if(w[i]>wmax) {wmax=w[i]; izmax=iz;}
114 }
115
116 /* Terminate if wmax<=0.; it indicates satisfaction of the Kuhn-Tucker conditions */
117 if(wmax<=0.0) break;
118 j=index[izmax];
119
120 /* The sign of W[j] is ok for j to be moved to set P.
121 Begin the transformation and check new diagonal element to avoid
122 near linear dependence. */
123 double asave=a[j][npp1];
124 up=0.0;
125 nnls_lss_h12(1, npp1, npp1+1, m, a[j], &up, NULL);
126 double unorm=0.0;
127 if(nsetp!=0) for(int mi=0; mi<nsetp; mi++) unorm+=a[j][mi]*a[j][mi];
128 unorm=sqrt(unorm);
129 double d=unorm+fabs(a[j][npp1])*0.01;
130 if((d-unorm)>0.0) {
131 /* Col j is sufficiently independent. Copy B into ZZ, update ZZ
132 and solve for ztest ( = proposed new value for X[j] ) */
133 for(int mi=0; mi<m; mi++) zz[mi]=b[mi];
134 nnls_lss_h12(2, npp1, npp1+1, m, a[j], &up, zz);
135 double ztest=zz[npp1]/a[j][npp1];
136 /* See if ztest is positive */
137 if(ztest>0.) break;
138 }
139
140 /* Reject j as a candidate to be moved from set Z to set P. Restore
141 A[npp1,j], set W[j]=0., and loop back to test dual coefficients again */
142 a[j][npp1]=asave; w[j]=0.;
143 } /* while(1) */
144 if(wmax<=0.0) break;
145
146 /* Index j=INDEX[izmax] has been selected to be moved from set Z to set P.
147 Update B and indices, apply householder transformations to cols in
148 new set Z, zero sub-diagonal elements in col j, set W[j]=0. */
149 for(int mi=0; mi<m; mi++) b[mi]=zz[mi];
150 index[izmax]=index[iz1]; index[iz1]=j; iz1++; nsetp=npp1+1; npp1++;
151 if(iz1<=iz2)
152 for(int jz=iz1; jz<=iz2; jz++) {
153 jj=index[jz];
154 nnls_lss_h12(2, nsetp-1, npp1, m, &a[j][0], &up, a[jj]);
155 }
156 if(nsetp!=m) for(int mi=npp1; mi<m; mi++) a[j][mi]=0.;
157 w[j]=0.;
158
159 /* Solve the triangular system; store the solution temporarily in Z[] */
160 for(int mi=0; mi<nsetp; mi++) {
161 int ip=nsetp-(mi+1);
162 if(mi!=0) for(int ii=0; ii<=ip; ii++) zz[ii]-=a[jj][ii]*zz[ip+1];
163 jj=index[ip]; zz[ip]/=a[jj][ip];
164 }
165
166 /* Secondary loop begins here */
167 while(++iter<itmax) {
168 /* See if all new constrained coefficients are feasible; if not, compute alpha */
169 double alpha=2.0;
170 for(int ip=0; ip<nsetp; ip++) {
171 int ni=index[ip];
172 if(zz[ip]<=0.) {
173 double t=-x[ni]/(zz[ip]-x[ni]);
174 if(alpha>t) {alpha=t; jj=ip-1;}
175 }
176 }
177
178 /* If all new constrained coefficients are feasible then still alpha==2.
179 If so, then exit from the secondary loop to main loop */
180 if(alpha==2.0) break;
181
182 /* Use alpha (0.<alpha<1.) to interpolate between old X and new ZZ */
183 for(int ip=0; ip<nsetp; ip++) {
184 int ni=index[ip]; x[ni]+=alpha*(zz[ip]-x[ni]);
185 }
186
187 /* Modify A and B and the INDEX arrays to move coefficient i from set P to set Z. */
188 int pfeas=1;
189 k=index[jj+1];
190 do {
191 x[k]=0.;
192 if(jj!=(nsetp-1)) {
193 jj++;
194 for(int ni=jj+1; ni<nsetp; ni++) {
195 int ii=index[ni]; index[ni-1]=ii;
196 double ss, cc;
197 nnls_lss_g1(a[ii][ni-1], a[ii][ni], &cc, &ss, &a[ii][ni-1]);
198 a[ii][ni]=0.0;
199 for(int nj=0; nj<n; nj++) if(nj!=ii) {
200 /* Apply procedure G2 (CC,SS,A(J-1,L),A(J,L)) */
201 double temp=a[nj][ni-1];
202 a[nj][ni-1]=cc*temp+ss*a[nj][ni];
203 a[nj][ni]=-ss*temp+cc*a[nj][ni];
204 }
205 /* Apply procedure G2 (CC,SS,B(J-1),B(J)) */
206 double temp=b[ni-1]; b[ni-1]=cc*temp+ss*b[ni]; b[ni]=-ss*temp+cc*b[ni];
207 }
208 }
209 npp1=nsetp-1; nsetp--; iz1--; index[iz1]=k;
210
211 /* See if the remaining coefficients in set P are feasible; they should be because of
212 the way alpha was determined. If any are infeasible it is due to round-off error.
213 Any that are non-positive will be set to zero and moved from set P to set Z. */
214 for(jj=0, pfeas=1; jj<nsetp; jj++) {
215 k=index[jj]; if(x[k]<=0.) {pfeas=0; break;}
216 }
217 } while(pfeas==0);
218
219 /* Copy B[] into zz[], then solve again and loop back */
220 for(int mi=0; mi<m; mi++) zz[mi]=b[mi];
221 for(int mi=0; mi<nsetp; mi++) {
222 int ip=nsetp-(mi+1);
223 if(mi!=0) for(int ii=0; ii<=ip; ii++) zz[ii]-=a[jj][ii]*zz[ip+1];
224 jj=index[ip]; zz[ip]/=a[jj][ip];
225 }
226 } /* end of secondary loop */
227
228 if(iter>=itmax) break;
229 for(int ip=0; ip<nsetp; ip++) {k=index[ip]; x[k]=zz[ip];}
230 } /* end of main loop */
231
232 if(wp != NULL) {
233 if(npp1>=m) for(int ni=0; ni<n; ni++) w[ni]=0.;
234 }
235
236 /* Compute the norm of the final residual vector (sum-of-squares) */
237 if(rnorm != NULL) {
238 double ss=0.0;
239 if(npp1<m) for(int mi=npp1; mi<m; mi++) ss+=(b[mi]*b[mi]);
240 *rnorm=ss;
241 }
242
243 /* Free working space, if it was allocated here */
244 if(wp==NULL) free(w);
245 if(zzp==NULL) free(zz);
246 if(indexp==NULL) free(index);
247 if(iter>=itmax) return(1);
248 return(0);
249} /* nnls */
250/*****************************************************************************/
251
252/*****************************************************************************/
261 int N,
263 int M,
265 double **A,
267 double *b,
269 double *weight
270) {
271 int n, m;
272 double *w;
273
274 /* Check the arguments */
275 if(N<1 || M<1 || A==NULL || b==NULL || weight==NULL) return(1);
276
277 /* Allocate memory */
278 w=(double*)malloc(M*sizeof(double)); if(w==NULL) return(2);
279
280 /* Check that weights are not zero and get the square roots of them to w[] */
281 for(m=0; m<M; m++) {
282 if(weight[m]<=1.0e-20) w[m]=0.0;
283 else w[m]=sqrt(weight[m]);
284 }
285
286 /* Multiply rows of matrix A and elements of vector b with weights*/
287 for(m=0; m<M; m++) {
288 for(n=0; n<N; n++) {
289 A[n][m]*=w[m];
290 }
291 b[m]*=w[m];
292 }
293
294 free(w);
295 return(0);
296}
297/*****************************************************************************/
298
299/*****************************************************************************/
310 int N,
312 int M,
314 double **A,
316 double *b,
318 double *sweight
319) {
320 int n, m;
321
322 /* Check the arguments */
323 if(N<1 || M<1 || A==NULL || b==NULL || sweight==NULL) return(1);
324
325 /* Multiply rows of matrix A and elements of vector b with weights*/
326 for(m=0; m<M; m++) {
327 for(n=0; n<N; n++) {
328 A[n][m]*=sweight[m];
329 }
330 b[m]*=sweight[m];
331 }
332
333 return(0);
334}
335/*****************************************************************************/
336
337/*****************************************************************************/
339
343int nnls_lss_h12(
346 int mode,
348 int lpivot,
350 int l1,
352 int m,
358 double *u,
361 double *up,
365 double *cm
366) {
367 /* Check parameters */
368 if(mode!=1 && mode!=2) return(1);
369 if(u==NULL || up==NULL) return(2);
370 if(lpivot<0 || l1<0 || m<0) return(3);
371 if(lpivot>=m || lpivot>=l1 || l1>m) return(4);
372
373 double cl = fabs(u[lpivot]);
374 if(mode==2 && cl<=0.) return(0);
375
376 if(mode==1) { /* Construct the transformation */
377 /* trying to compensate overflow */
378 for(int j=l1; j<m; j++) { // finding maximum
379 cl = fmax(fabs(u[j]), cl);
380 }
381 // zero vector?
382 if(cl<=0.) return(0);
383
384 double clinv=1.0/cl;
385 // cl = sqrt( (u[pivot]*clinv)^2 + sigma(i=l1..m)( (u[i]*clinv)^2 ) )
386 double d1=u[lpivot]*clinv;
387 double sm=d1*d1;
388 for(int j=l1; j<m; j++) {
389 double d2=u[j]*clinv;
390 sm+=d2*d2;
391 }
392 cl*=sqrt(sm);
393 if(u[lpivot] > 0.) cl=-cl;
394 *up = u[lpivot] - cl;
395 u[lpivot]=cl;
396 }
397
398 // no vectors where to apply? only change pivot vector!
399 double b=(*up)*u[lpivot];
400
401 /* b must be non-positive here; if b>=0., then return */
402 if(b>=0.0) return(0); // was if(b==0) before 2013-06-22
403
404 // Transform the cm vector, if requested
405 if(cm!=NULL) {
406 double sm = cm[lpivot] * (*up);
407 for(int k=l1; k<m; k++) sm += cm[k] * u[k];
408 if(sm!=0.0) {
409 sm *= (1.0/b);
410 cm[lpivot] += sm*(*up);
411 for(int k=l1; k<m; k++) cm[k] += u[k]*sm;
412 }
413 }
414
415 return(0);
416} /* nnls_lss_h12 */
417/*****************************************************************************/
418
419/*****************************************************************************/
427void nnls_lss_g1(double a, double b, double *cterm, double *sterm, double *sig)
428{
429 double d1, xr, yr;
430
431 if(fabs(a)>fabs(b)) {
432 xr=b/a; d1=xr; yr=hypot(d1, 1.0); d1=1./yr;
433 *cterm=copysign(d1, a);
434 *sterm=(*cterm)*xr; *sig=fabs(a)*yr;
435 } else if(b!=0.) {
436 xr=a/b; d1=xr; yr=hypot(d1, 1.0); d1=1./yr;
437 *sterm=copysign(d1, b);
438 *cterm=(*sterm)*xr; *sig=fabs(b)*yr;
439 } else {
440 *sig=0.; *cterm=0.; *sterm=1.;
441 }
442} /* nnls_lss_g1 */
444/*****************************************************************************/
445
446/*****************************************************************************/
int nnlsWghtSquared(int N, int M, double **A, double *b, double *sweight)
Definition nnls.c:308
int nnls(double **a, int m, int n, double *b, double *x, double *rnorm, double *wp, double *zzp, int *indexp)
Definition nnls.c:43
int nnlsWght(int N, int M, double **A, double *b, double *weight)
Definition nnls.c:259
Header file for library libtpcextensions.
Header file for libtpclinopt.