Mercurial > hg > nnls-chroma
comparison nnls.cpp @ 2:957e1fde20df matthiasm-plugin
dictionary matrix, included nnls, next step will be nnls computation
author | matthiasm |
---|---|
date | Wed, 19 May 2010 11:39:23 +0000 |
parents | |
children | 8360483a026e |
comparison
equal
deleted
inserted
replaced
1:2a491d71057d | 2:957e1fde20df |
---|---|
1 // $Id: nnls.cc,v 1.1.2.1 2003/03/06 16:28:07 suvrit Exp $ | |
2 // File: nnls.cc | |
3 // Implements the Lawson-Hanson NNLS algorithm | |
4 // Copied over from nnls.c so i don't ahve copyright on this | |
5 //...somebody else has.....don't know if this should be under GPL or LGPL or | |
6 // whatever, but i'll put a lil note here anyways: | |
7 | |
8 // Copyright (C) 2004 Lawson-Hanson | |
9 // Modifications to adapt to c++ by Suvrit Sra. | |
10 | |
11 // This program is free software; you can redistribute it and/or | |
12 // modify it under the terms of the GNU General Public License | |
13 // as published by the Free Software Foundation; either version 2 | |
14 // of the License, or (at your option) any later version. | |
15 | |
16 // This program is distributed in the hope that it will be useful, | |
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
19 // GNU General Public License for more details. | |
20 | |
21 // You should have received a copy of the GNU General Public License | |
22 // along with this program; if not, write to the Free Software | |
23 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
24 | |
25 | |
26 #include "nnls.h" | |
27 | |
28 double d_sign(double& a, double& b) | |
29 { | |
30 double x; | |
31 x = (a >= 0 ? a : - a); | |
32 return (b >= 0 ? x : -x); | |
33 } | |
34 | |
35 /* Table of constant values */ | |
36 | |
37 int c__1 = 1; | |
38 int c__0 = 0; | |
39 int c__2 = 2; | |
40 | |
41 | |
42 int nnls(double* a, int mda, int m, int n, double* b, | |
43 double* x, double* rnorm, double* w, double* zz, int* index, | |
44 int* mode) | |
45 { | |
46 /* System generated locals */ | |
47 int a_dim1, a_offset, idx1, idx2; | |
48 double d1, d2; | |
49 | |
50 | |
51 /* Local variables */ | |
52 static int iter; | |
53 static double temp, wmax; | |
54 static int i__, j, l; | |
55 static double t, alpha, asave; | |
56 static int itmax, izmax, nsetp; | |
57 static double unorm, ztest, cc; | |
58 double dummy[2]; | |
59 static int ii, jj, ip; | |
60 static double sm; | |
61 static int iz, jz; | |
62 static double up, ss; | |
63 static int rtnkey, iz1, iz2, npp1; | |
64 | |
65 /* ------------------------------------------------------------------ | |
66 */ | |
67 /* int INDEX(N) */ | |
68 /* double precision A(MDA,N), B(M), W(N), X(N), ZZ(M) */ | |
69 /* ------------------------------------------------------------------ | |
70 */ | |
71 /* Parameter adjustments */ | |
72 a_dim1 = mda; | |
73 a_offset = a_dim1 + 1; | |
74 a -= a_offset; | |
75 --b; | |
76 --x; | |
77 --w; | |
78 --zz; | |
79 --index; | |
80 | |
81 /* Function Body */ | |
82 *mode = 1; | |
83 if (m <= 0 || n <= 0) { | |
84 *mode = 2; | |
85 return 0; | |
86 } | |
87 iter = 0; | |
88 itmax = n * 3; | |
89 | |
90 /* INITIALIZE THE ARRAYS INDEX() AND X(). */ | |
91 | |
92 idx1 = n; | |
93 for (i__ = 1; i__ <= idx1; ++i__) { | |
94 x[i__] = 0.; | |
95 /* L20: */ | |
96 index[i__] = i__; | |
97 } | |
98 | |
99 iz2 = n; | |
100 iz1 = 1; | |
101 nsetp = 0; | |
102 npp1 = 1; | |
103 /* ****** MAIN LOOP BEGINS HERE ****** */ | |
104 L30: | |
105 /* QUIT IF ALL COEFFICIENTS ARE ALREADY IN THE SOLUTION. | |
106 */ | |
107 /* OR IF M COLS OF A HAVE BEEN TRIANGULARIZED. */ | |
108 | |
109 if (iz1 > iz2 || nsetp >= m) { | |
110 goto L350; | |
111 } | |
112 | |
113 /* COMPUTE COMPONENTS OF THE DUAL (NEGATIVE GRADIENT) VECTOR W(). | |
114 */ | |
115 | |
116 idx1 = iz2; | |
117 for (iz = iz1; iz <= idx1; ++iz) { | |
118 j = index[iz]; | |
119 sm = 0.; | |
120 idx2 = m; | |
121 for (l = npp1; l <= idx2; ++l) { | |
122 /* L40: */ | |
123 sm += a[l + j * a_dim1] * b[l]; | |
124 } | |
125 w[j] = sm; | |
126 /* L50: */ | |
127 } | |
128 /* FIND LARGEST POSITIVE W(J). */ | |
129 L60: | |
130 wmax = 0.; | |
131 idx1 = iz2; | |
132 for (iz = iz1; iz <= idx1; ++iz) { | |
133 j = index[iz]; | |
134 if (w[j] > wmax) { | |
135 wmax = w[j]; | |
136 izmax = iz; | |
137 } | |
138 /* L70: */ | |
139 } | |
140 | |
141 /* IF WMAX .LE. 0. GO TO TERMINATION. */ | |
142 /* THIS INDICATES SATISFACTION OF THE KUHN-TUCKER CONDITIONS. | |
143 */ | |
144 | |
145 if (wmax <= 0.) { | |
146 goto L350; | |
147 } | |
148 iz = izmax; | |
149 j = index[iz]; | |
150 | |
151 /* THE SIGN OF W(J) IS OK FOR J TO BE MOVED TO SET P. */ | |
152 /* BEGIN THE TRANSFORMATION AND CHECK NEW DIAGONAL ELEMENT TO AVOID */ | |
153 /* NEAR LINEAR DEPENDENCE. */ | |
154 | |
155 asave = a[npp1 + j * a_dim1]; | |
156 idx1 = npp1 + 1; | |
157 h12(c__1, &npp1, &idx1, m, &a[j * a_dim1 + 1], &c__1, &up, dummy, & | |
158 c__1, &c__1, &c__0); | |
159 unorm = 0.; | |
160 if (nsetp != 0) { | |
161 idx1 = nsetp; | |
162 for (l = 1; l <= idx1; ++l) { | |
163 /* L90: */ | |
164 /* Computing 2nd power */ | |
165 d1 = a[l + j * a_dim1]; | |
166 unorm += d1 * d1; | |
167 } | |
168 } | |
169 unorm = sqrt(unorm); | |
170 d2 = unorm + (d1 = a[npp1 + j * a_dim1], nnls_abs(d1)) * .01; | |
171 if ((d2- unorm) > 0.) { | |
172 | |
173 /* COL J IS SUFFICIENTLY INDEPENDENT. COPY B INTO ZZ, UPDATE Z | |
174 Z */ | |
175 /* AND SOLVE FOR ZTEST ( = PROPOSED NEW VALUE FOR X(J) ). */ | |
176 | |
177 idx1 = m; | |
178 for (l = 1; l <= idx1; ++l) { | |
179 /* L120: */ | |
180 zz[l] = b[l]; | |
181 } | |
182 idx1 = npp1 + 1; | |
183 h12(c__2, &npp1, &idx1, m, &a[j * a_dim1 + 1], &c__1, &up, (zz+1), & | |
184 c__1, &c__1, &c__1); | |
185 ztest = zz[npp1] / a[npp1 + j * a_dim1]; | |
186 | |
187 /* SEE IF ZTEST IS POSITIVE */ | |
188 | |
189 if (ztest > 0.) { | |
190 goto L140; | |
191 } | |
192 } | |
193 | |
194 /* REJECT J AS A CANDIDATE TO BE MOVED FROM SET Z TO SET P. */ | |
195 /* RESTORE A(NPP1,J), SET W(J)=0., AND LOOP BACK TO TEST DUAL */ | |
196 /* COEFFS AGAIN. */ | |
197 | |
198 a[npp1 + j * a_dim1] = asave; | |
199 w[j] = 0.; | |
200 goto L60; | |
201 | |
202 /* THE INDEX J=INDEX(IZ) HAS BEEN SELECTED TO BE MOVED FROM */ | |
203 /* SET Z TO SET P. UPDATE B, UPDATE INDICES, APPLY HOUSEHOLDER */ | |
204 /* TRANSFORMATIONS TO COLS IN NEW SET Z, ZERO SUBDIAGONAL ELTS IN */ | |
205 /* COL J, SET W(J)=0. */ | |
206 | |
207 L140: | |
208 idx1 = m; | |
209 for (l = 1; l <= idx1; ++l) { | |
210 /* L150: */ | |
211 b[l] = zz[l]; | |
212 } | |
213 | |
214 index[iz] = index[iz1]; | |
215 index[iz1] = j; | |
216 ++iz1; | |
217 nsetp = npp1; | |
218 ++npp1; | |
219 | |
220 if (iz1 <= iz2) { | |
221 idx1 = iz2; | |
222 for (jz = iz1; jz <= idx1; ++jz) { | |
223 jj = index[jz]; | |
224 h12(c__2, &nsetp, &npp1, m, | |
225 &a[j * a_dim1 + 1], &c__1, &up, | |
226 &a[jj * a_dim1 + 1], &c__1, &mda, &c__1); | |
227 /* L160: */ | |
228 } | |
229 } | |
230 | |
231 if (nsetp != m) { | |
232 idx1 = m; | |
233 for (l = npp1; l <= idx1; ++l) { | |
234 /* L180: */ | |
235 // SS: CHECK THIS DAMAGE.... | |
236 a[l + j * a_dim1] = 0.; | |
237 } | |
238 } | |
239 | |
240 w[j] = 0.; | |
241 /* SOLVE THE TRIANGULAR SYSTEM. */ | |
242 /* STORE THE SOLUTION TEMPORARILY IN ZZ(). | |
243 */ | |
244 rtnkey = 1; | |
245 goto L400; | |
246 L200: | |
247 | |
248 /* ****** SECONDARY LOOP BEGINS HERE ****** */ | |
249 | |
250 /* ITERATION COUNTER. */ | |
251 | |
252 L210: | |
253 ++iter; | |
254 if (iter > itmax) { | |
255 *mode = 3; | |
256 /* The following lines were replaced after the f2c translation */ | |
257 /* s_wsfe(&io___22); */ | |
258 /* do_fio(&c__1, " NNLS quitting on iteration count.", 34L); */ | |
259 /* e_wsfe(); */ | |
260 fprintf(stdout, "\n NNLS quitting on iteration count.\n"); | |
261 fflush(stdout); | |
262 goto L350; | |
263 } | |
264 | |
265 /* SEE IF ALL NEW CONSTRAINED COEFFS ARE FEASIBLE. */ | |
266 /* IF NOT COMPUTE ALPHA. */ | |
267 | |
268 alpha = 2.; | |
269 idx1 = nsetp; | |
270 for (ip = 1; ip <= idx1; ++ip) { | |
271 l = index[ip]; | |
272 if (zz[ip] <= 0.) { | |
273 t = -x[l] / (zz[ip] - x[l]); | |
274 if (alpha > t) { | |
275 alpha = t; | |
276 jj = ip; | |
277 } | |
278 } | |
279 /* L240: */ | |
280 } | |
281 | |
282 /* IF ALL NEW CONSTRAINED COEFFS ARE FEASIBLE THEN ALPHA WILL */ | |
283 /* STILL = 2. IF SO EXIT FROM SECONDARY LOOP TO MAIN LOOP. */ | |
284 | |
285 if (alpha == 2.) { | |
286 goto L330; | |
287 } | |
288 | |
289 /* OTHERWISE USE ALPHA WHICH WILL BE BETWEEN 0. AND 1. TO */ | |
290 /* INTERPOLATE BETWEEN THE OLD X AND THE NEW ZZ. */ | |
291 | |
292 idx1 = nsetp; | |
293 for (ip = 1; ip <= idx1; ++ip) { | |
294 l = index[ip]; | |
295 x[l] += alpha * (zz[ip] - x[l]); | |
296 /* L250: */ | |
297 } | |
298 | |
299 /* MODIFY A AND B AND THE INDEX ARRAYS TO MOVE COEFFICIENT I */ | |
300 /* FROM SET P TO SET Z. */ | |
301 | |
302 i__ = index[jj]; | |
303 L260: | |
304 x[i__] = 0.; | |
305 | |
306 if (jj != nsetp) { | |
307 ++jj; | |
308 idx1 = nsetp; | |
309 for (j = jj; j <= idx1; ++j) { | |
310 ii = index[j]; | |
311 index[j - 1] = ii; | |
312 g1(&a[j - 1 + ii * a_dim1], &a[j + ii * a_dim1], | |
313 &cc, &ss, &a[j - 1 + ii * a_dim1]); | |
314 // SS: CHECK THIS DAMAGE... | |
315 a[j + ii * a_dim1] = 0.; | |
316 idx2 = n; | |
317 for (l = 1; l <= idx2; ++l) { | |
318 if (l != ii) { | |
319 | |
320 /* Apply procedure G2 (CC,SS,A(J-1,L),A(J, | |
321 L)) */ | |
322 | |
323 temp = a[j - 1 + l * a_dim1]; | |
324 // SS: CHECK THIS DAMAGE | |
325 a[j - 1 + l * a_dim1] = cc * temp + ss * a[j + l * a_dim1]; | |
326 a[j + l * a_dim1] = -ss * temp + cc * a[j + l * a_dim1]; | |
327 } | |
328 /* L270: */ | |
329 } | |
330 | |
331 /* Apply procedure G2 (CC,SS,B(J-1),B(J)) */ | |
332 | |
333 temp = b[j - 1]; | |
334 b[j - 1] = cc * temp + ss * b[j]; | |
335 b[j] = -ss * temp + cc * b[j]; | |
336 /* L280: */ | |
337 } | |
338 } | |
339 | |
340 npp1 = nsetp; | |
341 --nsetp; | |
342 --iz1; | |
343 index[iz1] = i__; | |
344 | |
345 /* SEE IF THE REMAINING COEFFS IN SET P ARE FEASIBLE. THEY SHOULD | |
346 */ | |
347 /* BE BECAUSE OF THE WAY ALPHA WAS DETERMINED. */ | |
348 /* IF ANY ARE INFEASIBLE IT IS DUE TO ROUND-OFF ERROR. ANY */ | |
349 /* THAT ARE NONPOSITIVE WILL BE SET TO ZERO */ | |
350 /* AND MOVED FROM SET P TO SET Z. */ | |
351 | |
352 idx1 = nsetp; | |
353 for (jj = 1; jj <= idx1; ++jj) { | |
354 i__ = index[jj]; | |
355 if (x[i__] <= 0.) { | |
356 goto L260; | |
357 } | |
358 /* L300: */ | |
359 } | |
360 | |
361 /* COPY B( ) INTO ZZ( ). THEN SOLVE AGAIN AND LOOP BACK. */ | |
362 | |
363 idx1 = m; | |
364 for (i__ = 1; i__ <= idx1; ++i__) { | |
365 /* L310: */ | |
366 zz[i__] = b[i__]; | |
367 } | |
368 rtnkey = 2; | |
369 goto L400; | |
370 L320: | |
371 goto L210; | |
372 /* ****** END OF SECONDARY LOOP ****** */ | |
373 | |
374 L330: | |
375 idx1 = nsetp; | |
376 for (ip = 1; ip <= idx1; ++ip) { | |
377 i__ = index[ip]; | |
378 /* L340: */ | |
379 x[i__] = zz[ip]; | |
380 } | |
381 /* ALL NEW COEFFS ARE POSITIVE. LOOP BACK TO BEGINNING. */ | |
382 goto L30; | |
383 | |
384 /* ****** END OF MAIN LOOP ****** */ | |
385 | |
386 /* COME TO HERE FOR TERMINATION. */ | |
387 /* COMPUTE THE NORM OF THE FINAL RESIDUAL VECTOR. */ | |
388 | |
389 L350: | |
390 sm = 0.; | |
391 if (npp1 <= m) { | |
392 idx1 = m; | |
393 for (i__ = npp1; i__ <= idx1; ++i__) { | |
394 /* L360: */ | |
395 /* Computing 2nd power */ | |
396 d1 = b[i__]; | |
397 sm += d1 * d1; | |
398 } | |
399 } else { | |
400 idx1 = n; | |
401 for (j = 1; j <= idx1; ++j) { | |
402 /* L380: */ | |
403 w[j] = 0.; | |
404 } | |
405 } | |
406 *rnorm = sqrt(sm); | |
407 return 0; | |
408 | |
409 /* THE FOLLOWING BLOCK OF CODE IS USED AS AN INTERNAL SUBROUTINE */ | |
410 /* TO SOLVE THE TRIANGULAR SYSTEM, PUTTING THE SOLUTION IN ZZ(). */ | |
411 | |
412 L400: | |
413 idx1 = nsetp; | |
414 for (l = 1; l <= idx1; ++l) { | |
415 ip = nsetp + 1 - l; | |
416 if (l != 1) { | |
417 idx2 = ip; | |
418 for (ii = 1; ii <= idx2; ++ii) { | |
419 zz[ii] -= a[ii + jj * a_dim1] * zz[ip + 1]; | |
420 /* L410: */ | |
421 } | |
422 } | |
423 jj = index[ip]; | |
424 zz[ip] /= a[ip + jj * a_dim1]; | |
425 /* L430: */ | |
426 } | |
427 switch ((int)rtnkey) { | |
428 case 1: goto L200; | |
429 case 2: goto L320; | |
430 } | |
431 | |
432 /* The next line was added after the f2c translation to keep | |
433 compilers from complaining about a void return from a non-void | |
434 function. */ | |
435 return 0; | |
436 | |
437 } /* nnls_ */ | |
438 | |
439 | |
440 int g1(double* a, double* b, double* cterm, double* sterm, double* sig) | |
441 { | |
442 /* System generated locals */ | |
443 double d; | |
444 | |
445 static double xr, yr; | |
446 | |
447 | |
448 if (nnls_abs(*a) > nnls_abs(*b)) { | |
449 xr = *b / *a; | |
450 /* Computing 2nd power */ | |
451 d = xr; | |
452 yr = sqrt(d * d + 1.); | |
453 d = 1. / yr; | |
454 *cterm = d_sign(d, *a); | |
455 *sterm = *cterm * xr; | |
456 *sig = nnls_abs(*a) * yr; | |
457 return 0; | |
458 } | |
459 if (*b != 0.) { | |
460 xr = *a / *b; | |
461 /* Computing 2nd power */ | |
462 d = xr; | |
463 yr = sqrt(d * d + 1.); | |
464 d = 1. / yr; | |
465 *sterm = d_sign(d, *b); | |
466 *cterm = *sterm * xr; | |
467 *sig = nnls_abs(*b) * yr; | |
468 return 0; | |
469 } | |
470 *sig = 0.; | |
471 *cterm = 0.; | |
472 *sterm = 1.; | |
473 return 0; | |
474 } /* g1_ */ | |
475 | |
476 | |
477 /* See nnls.h for explanation */ | |
478 int h12(int mode, int* lpivot, int* l1, | |
479 int m, double* u, int* iue, double* up, double* c__, | |
480 int* ice, int* icv, int* ncv) | |
481 { | |
482 /* System generated locals */ | |
483 int u_dim1, u_offset, idx1, idx2; | |
484 double d, d2; | |
485 | |
486 /* Builtin functions */ | |
487 /* The following line was commented out after the f2c translation */ | |
488 /* double sqrt(); */ | |
489 | |
490 /* Local variables */ | |
491 static int incr; | |
492 static double b; | |
493 static int i__, j; | |
494 static double clinv; | |
495 static int i2, i3, i4; | |
496 static double cl, sm; | |
497 | |
498 /* ------------------------------------------------------------------ | |
499 */ | |
500 /* double precision U(IUE,M) */ | |
501 /* ------------------------------------------------------------------ | |
502 */ | |
503 /* Parameter adjustments */ | |
504 u_dim1 = *iue; | |
505 u_offset = u_dim1 + 1; | |
506 u -= u_offset; | |
507 --c__; | |
508 | |
509 /* Function Body */ | |
510 if (0 >= *lpivot || *lpivot >= *l1 || *l1 > m) { | |
511 return 0; | |
512 } | |
513 cl = (d = u[*lpivot * u_dim1 + 1], nnls_abs(d)); | |
514 if (mode == 2) { | |
515 goto L60; | |
516 } | |
517 /* ****** CONSTRUCT THE TRANSFORMATION. ****** | |
518 */ | |
519 idx1 = m; | |
520 for (j = *l1; j <= idx1; ++j) { | |
521 /* L10: */ | |
522 /* Computing MAX */ | |
523 d2 = (d = u[j * u_dim1 + 1], nnls_abs(d)); | |
524 cl = nnls_max(d2,cl); | |
525 } | |
526 if (cl <= 0.) { | |
527 goto L130; | |
528 } else { | |
529 goto L20; | |
530 } | |
531 L20: | |
532 clinv = 1. / cl; | |
533 /* Computing 2nd power */ | |
534 d = u[*lpivot * u_dim1 + 1] * clinv; | |
535 sm = d * d; | |
536 idx1 = m; | |
537 for (j = *l1; j <= idx1; ++j) { | |
538 /* L30: */ | |
539 /* Computing 2nd power */ | |
540 d = u[j * u_dim1 + 1] * clinv; | |
541 sm += d * d; | |
542 } | |
543 cl *= sqrt(sm); | |
544 if (u[*lpivot * u_dim1 + 1] <= 0.) { | |
545 goto L50; | |
546 } else { | |
547 goto L40; | |
548 } | |
549 L40: | |
550 cl = -cl; | |
551 L50: | |
552 *up = u[*lpivot * u_dim1 + 1] - cl; | |
553 u[*lpivot * u_dim1 + 1] = cl; | |
554 goto L70; | |
555 /* ****** APPLY THE TRANSFORMATION I+U*(U**T)/B TO C. ****** | |
556 */ | |
557 | |
558 L60: | |
559 if (cl <= 0.) { | |
560 goto L130; | |
561 } else { | |
562 goto L70; | |
563 } | |
564 L70: | |
565 if (*ncv <= 0) { | |
566 return 0; | |
567 } | |
568 b = *up * u[*lpivot * u_dim1 + 1]; | |
569 /* B MUST BE NONPOSITIVE HERE. IF B = 0., RETURN. | |
570 */ | |
571 | |
572 if (b >= 0.) { | |
573 goto L130; | |
574 } else { | |
575 goto L80; | |
576 } | |
577 L80: | |
578 b = 1. / b; | |
579 i2 = 1 - *icv + *ice * (*lpivot - 1); | |
580 incr = *ice * (*l1 - *lpivot); | |
581 idx1 = *ncv; | |
582 for (j = 1; j <= idx1; ++j) { | |
583 i2 += *icv; | |
584 i3 = i2 + incr; | |
585 i4 = i3; | |
586 sm = c__[i2] * *up; | |
587 idx2 = m; | |
588 for (i__ = *l1; i__ <= idx2; ++i__) { | |
589 sm += c__[i3] * u[i__ * u_dim1 + 1]; | |
590 /* L90: */ | |
591 i3 += *ice; | |
592 } | |
593 if (sm != 0.) { | |
594 goto L100; | |
595 } else { | |
596 goto L120; | |
597 } | |
598 L100: | |
599 sm *= b; | |
600 c__[i2] += sm * *up; | |
601 idx2 = m; | |
602 for (i__ = *l1; i__ <= idx2; ++i__) { | |
603 c__[i4] += sm * u[i__ * u_dim1 + 1]; | |
604 /* L110: */ | |
605 i4 += *ice; | |
606 } | |
607 L120: | |
608 ; | |
609 } | |
610 L130: | |
611 return 0; | |
612 } /* h12 */ | |
613 |