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