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