TPCCLIB
Toggle main menu visibility
Loading...
Searching...
No Matches
libtpclinopt
nnlsq.c
Go to the documentation of this file.
1
12
/*****************************************************************************/
13
#include "tpcclibConfig.h"
14
/*****************************************************************************/
15
#include <stdio.h>
16
#include <stdlib.h>
17
#include <math.h>
18
/*****************************************************************************/
19
#include "
tpcextensions.h
"
20
/*****************************************************************************/
21
#include "
tpclinopt.h
"
22
/*****************************************************************************/
23
24
/*****************************************************************************/
25
// Comment this out to NOT test for buffer overflow
26
//#define TEST_BUFOVERFLOW 1
27
/*****************************************************************************/
28
29
/*****************************************************************************/
31
/* Local function definitions */
32
int
nnlsq_lss_h12(
int
mode,
int
lpivot,
int
l1,
int
m,
double
*u,
double
*up,
double
*cm);
33
void
nnlsq_lss_g1(
double
a,
double
b,
double
*cterm,
double
*sterm,
double
*sig);
35
/*****************************************************************************/
36
37
/*****************************************************************************/
55
int
nnlsq
(
62
NNLSQDATA
*d,
64
int
verbose
65
) {
66
if
(verbose>0) {printf(
"%s()\n"
, __func__); fflush(stdout);}
67
68
/* Check the data */
69
if
(d==NULL || d->
m
<1 || d->
n
<1 || d->
a
==NULL || d->
b
==NULL ||
70
d->
x
==NULL || d->
w
==NULL || d->
zz
==NULL || d->
index
==NULL)
71
return
(2);
72
if
(!(d->
depf
>=1.0E-08) || !(d->
depf
<0.5))
return
(3);
73
74
/* Initialize */
75
for
(
int
ni=0; ni<d->
n
; ni++) d->
x
[ni]=0.0;
76
for
(
int
ni=0; ni<d->
n
; ni++) d->
index
[ni]=ni;
77
d->
rnorm
=nan(
""
);
78
int
iz1=0;
79
int
iz2=d->
n
-1;
80
int
nsetp=0;
81
int
npp1=0;
82
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
itermax, iter=0;
88
if
(d->
iternr
>=3) itermax=d->
iternr
;
else
itermax=3*d->
n
;
89
int
j=0, jj=0;
90
while
(iz1<=iz2 && nsetp<d->m) {
91
/* Compute components of the dual (negative gradient) vector W[] */
92
for
(
int
iz=iz1; iz<=iz2; iz++) {
93
int
ni=d->
index
[iz];
94
double
sm=0.;
95
for
(
int
mi=npp1; mi<d->
m
; mi++) sm+=d->
a
[ni][mi]*d->
b
[mi];
96
d->
w
[ni]=sm;
97
}
98
99
double
wmax;
100
int
izmax=0;
101
while
(1) {
102
103
/* Find largest positive W */
104
wmax=0.0;
105
for
(
int
iz=iz1; iz<=iz2; iz++) {
106
int
i=d->
index
[iz];
107
if
(d->
w
[i]>wmax) {wmax=d->
w
[i]; izmax=iz;}
108
}
109
110
/* Terminate if wmax<=0.; it indicates satisfaction of the Kuhn-Tucker conditions */
111
if
(wmax<=0.0)
break
;
112
113
/* The sign of W[j] is ok for j to be moved to set P.
114
Begin the transformation and check new diagonal element to avoid near linear dependence. */
115
j=d->
index
[izmax];
116
double
asave=d->
a
[j][npp1];
117
// up=0.0;
118
if
(nnlsq_lss_h12(1, npp1, npp1+1, d->
m
, d->
a
[j], &up, NULL))
return
(2);
119
double
unorm=0.0;
120
if
(nsetp!=0)
for
(
int
mi=0; mi<nsetp; mi++) unorm+=d->
a
[j][mi]*d->
a
[j][mi];
121
unorm=sqrt(unorm);
122
double
e=unorm+fabs(d->
a
[j][npp1])*d->
depf
;
123
if
((e-unorm)>0.0) {
124
/* Col j is sufficiently independent. Copy B into ZZ, update ZZ
125
and solve for ztest ( = proposed new value for X[j] ) */
126
for
(
int
mi=0; mi<d->
m
; mi++) d->
zz
[mi]=d->
b
[mi];
127
nnlsq_lss_h12(2, npp1, npp1+1, d->
m
, d->
a
[j], &up, d->
zz
);
128
double
ztest=d->
zz
[npp1]/d->
a
[j][npp1];
129
/* See if ztest is positive */
130
if
(ztest>0.)
break
;
131
}
132
133
/* Reject j as a candidate to be moved from set Z to set P. Restore
134
A[npp1,j], set W[j]=0., and loop back to test dual coefficients again */
135
d->
a
[j][npp1]=asave; d->
w
[j]=0.;
136
}
/* while(1) */
137
if
(wmax<=0.0)
break
;
138
139
/* Index j=INDEX[izmax] has been selected to be moved from set Z to set P.
140
Update B and indices, apply householder transformations to cols in
141
new set Z, zero sub-diagonal elements in col j, set W[j]=0. */
142
for
(
int
mi=0; mi<d->
m
; mi++) d->
b
[mi]=d->
zz
[mi];
143
d->
index
[izmax]=d->
index
[iz1]; d->
index
[iz1]=j; iz1++; nsetp=npp1+1; npp1++;
144
if
(iz1<=iz2)
145
for
(
int
jz=iz1; jz<=iz2; jz++) {
146
jj=d->
index
[jz];
147
nnlsq_lss_h12(2, nsetp-1, npp1, d->
m
, d->
a
[j], &up, d->
a
[jj]);
148
}
149
if
(nsetp!=d->
m
)
for
(
int
mi=npp1; mi<d->
m
; mi++) d->
a
[j][mi]=0.;
150
d->
w
[j]=0.;
151
152
/* Solve the triangular system; store the solution temporarily in Z[] */
153
for
(
int
mi=0; mi<nsetp; mi++) {
154
int
ip=nsetp-(mi+1);
155
if
(mi!=0)
for
(
int
ii=0; ii<=ip; ii++) d->
zz
[ii]-=d->
a
[jj][ii]*d->
zz
[ip+1];
156
jj=d->
index
[ip]; d->
zz
[ip]/=d->
a
[jj][ip];
157
}
158
159
/* Secondary loop begins here */
160
while
(++iter<itermax) {
161
/* See if all new constrained coefficients are feasible; if not, compute alpha */
162
double
alpha=2.0;
163
for
(
int
ip=0; ip<nsetp; ip++) {
164
int
ni=d->
index
[ip];
165
if
(d->
zz
[ip]<=0.) {
166
double
t=-d->
x
[ni]/(d->
zz
[ip]-d->
x
[ni]);
167
if
(alpha>t) {alpha=t; jj=ip-1;}
168
}
169
}
170
171
/* If all new constrained coefficients are feasible then still alpha==2.
172
If so, then exit from the secondary loop to main loop */
173
if
(alpha==2.0)
break
;
174
175
/* Use alpha (0.<alpha<1.) to interpolate between old X and new ZZ */
176
for
(
int
ip=0; ip<nsetp; ip++) {
177
int
ni=d->
index
[ip]; d->
x
[ni]+=alpha*(d->
zz
[ip]-d->
x
[ni]);
178
}
179
180
/* Modify A and B and the INDEX arrays to move coefficient i from set P to set Z. */
181
int
pfeas=1;
182
int
k=d->
index
[jj+1];
183
do
{
184
d->
x
[k]=0.;
185
if
(jj!=(nsetp-1)) {
186
jj++;
187
for
(
int
ni=jj+1; ni<nsetp; ni++) {
188
int
ii=d->
index
[ni]; d->
index
[ni-1]=ii;
189
double
ss, cc;
190
nnlsq_lss_g1(d->
a
[ii][ni-1], d->
a
[ii][ni], &cc, &ss, &d->
a
[ii][ni-1]);
191
d->
a
[ii][ni]=0.0;
192
for
(
int
nj=0; nj<d->
n
; nj++)
if
(nj!=ii) {
193
/* Apply procedure G2 (CC,SS,A(J-1,L),A(J,L)) */
194
double
temp=d->
a
[nj][ni-1];
195
d->
a
[nj][ni-1]=cc*temp+ss*d->
a
[nj][ni];
196
d->
a
[nj][ni]=-ss*temp+cc*d->
a
[nj][ni];
197
}
198
/* Apply procedure G2 (CC,SS,B(J-1),B(J)) */
199
double
temp=d->
b
[ni-1];
200
d->
b
[ni-1]=cc*temp+ss*d->
b
[ni];
201
d->
b
[ni]=-ss*temp+cc*d->
b
[ni];
202
}
203
}
204
npp1=nsetp-1; nsetp--; iz1--; d->
index
[iz1]=k;
205
206
/* See if the remaining coefficients in set P are feasible; they should be because of
207
the way alpha was determined. If any are infeasible it is due to round-off error.
208
Any that are non-positive will be set to zero and moved from set P to set Z. */
209
pfeas=1;
210
for
(jj=0; jj<nsetp; jj++) {
211
k=d->
index
[jj];
if
(d->
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<d->
m
; mi++) d->
zz
[mi]=d->
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++) d->
zz
[ii]-=d->
a
[jj][ii]*d->
zz
[ip+1];
220
jj=d->
index
[ip]; d->
zz
[ip]/=d->
a
[jj][ip];
221
}
222
}
/* end of secondary loop */
223
224
if
(iter>=itermax)
break
;
225
for
(
int
ip=0; ip<nsetp; ip++) {
int
k=d->
index
[ip]; d->
x
[k]=d->
zz
[ip];}
226
}
/* end of main loop */
227
228
if
(npp1>=d->
m
)
for
(
int
ni=0; ni<d->
n
; ni++) d->
w
[ni]=0.;
229
230
/* Compute the norm of the final residual vector (sum-of-squares) */
231
d->
rnorm
=0.0;
232
for
(
int
mi=npp1; mi<d->
m
; mi++) d->
rnorm
+=(d->
b
[mi]*d->
b
[mi]);
233
234
d->
iternr
=iter;
235
if
(verbose>2) printf(
" %d iterations.\n"
, iter);
236
if
(iter>=itermax) {
237
if
(verbose>1) printf(
" max iterations reached.\n"
);
238
return
(1);
239
}
240
return
(0);
241
}
/* nnlsq */
242
/*****************************************************************************/
243
244
/*****************************************************************************/
246
250
int
nnlsq_lss_h12(
253
int
mode,
255
int
lpivot,
257
int
l1,
259
int
m,
265
double
*u,
268
double
*up,
272
double
*cm
273
) {
274
/* Check parameters */
275
if
(mode!=1 && mode!=2)
return
(1);
276
if
(u==NULL || up==NULL)
return
(2);
277
if
(lpivot<0 || l1<0 || m<0)
return
(3);
278
if
(lpivot>=m || lpivot>=l1 || l1>m)
return
(4);
279
280
double
cl = fabs(u[lpivot]);
281
if
(mode==2 && cl<=0.)
return
(0);
282
283
if
(mode==1) {
/* Construct the transformation */
284
/* trying to compensate overflow */
285
for
(
int
j=l1; j<m; j++) {
// finding maximum
286
cl = fmax(fabs(u[j]), cl);
287
}
288
// zero vector?
289
if
(cl<=0.)
return
(0);
290
291
double
clinv=1.0/cl;
292
// cl = sqrt( (u[pivot]*clinv)^2 + sigma(i=l1..m)( (u[i]*clinv)^2 ) )
293
double
d1=u[lpivot]*clinv;
294
double
sm=d1*d1;
295
for
(
int
j=l1; j<m; j++) {
296
double
d2=u[j]*clinv;
297
sm+=d2*d2;
298
}
299
cl*=sqrt(sm);
300
if
(u[lpivot] > 0.) cl=-cl;
301
*up = u[lpivot] - cl;
302
u[lpivot]=cl;
303
}
304
305
// no vectors where to apply? only change pivot vector!
306
double
b=(*up)*u[lpivot];
307
308
/* b must be non-positive here; if b>=0., then return */
309
if
(b>=0.0)
return
(0);
// was if(b==0) before 2013-06-22
310
311
// Transform the cm vector, if requested
312
if
(cm!=NULL) {
313
double
sm = cm[lpivot] * (*up);
314
for
(
int
k=l1; k<m; k++) sm += cm[k] * u[k];
315
if
(sm!=0.0) {
316
sm *= (1.0/b);
317
cm[lpivot] += sm*(*up);
318
for
(
int
k=l1; k<m; k++) cm[k] += u[k]*sm;
319
}
320
}
321
322
return
(0);
323
}
/* nnlsq_lss_h12 */
324
/*****************************************************************************/
325
326
/*****************************************************************************/
334
void
nnlsq_lss_g1(
double
a,
double
b,
double
*cterm,
double
*sterm,
double
*sig)
335
{
336
double
d1, xr, yr;
337
338
if
(fabs(a)>fabs(b)) {
339
xr=b/a; d1=xr; yr=hypot(d1, 1.0); d1=1./yr;
340
*cterm=copysign(d1, a);
341
*sterm=(*cterm)*xr; *sig=fabs(a)*yr;
342
}
else
if
(b!=0.) {
343
xr=a/b; d1=xr; yr=hypot(d1, 1.0); d1=1./yr;
344
*sterm=copysign(d1, b);
345
*cterm=(*sterm)*xr; *sig=fabs(b)*yr;
346
}
else
{
347
*sig=0.; *cterm=0.; *sterm=1.;
348
}
349
}
/* nnlsq_lss_g1 */
351
/*****************************************************************************/
352
353
/*****************************************************************************/
358
void
nnlsqDataInit
(
360
NNLSQDATA
*d
361
) {
362
if
(d==NULL)
return
;
363
d->
n
= d->
m
= 0;
364
d->
a
= NULL;
365
d->
b
= d->
x
= d->
w
= d->
zz
= d->
_data
= NULL;
366
d->
index
= NULL;
367
d->
rnorm
= 0.0;
368
d->
iternr
= 0;
369
d->
depf
= 0.01;
// default
370
}
371
/*****************************************************************************/
372
373
/*****************************************************************************/
379
void
nnlsqDataFree
(
381
NNLSQDATA
*d
382
) {
383
if
(d==NULL)
return
;
384
if
(d->
n
<1)
return
;
385
if
(d->
m
<1)
return
;
386
387
#ifdef TEST_BUFOVERFLOW
388
fprintf(stderr,
"testing if buffer overflow happened\n"
); fflush(stderr);
389
if
(d->
index
[d->
n
]!=999) fprintf(stderr,
"BUFFER OVERFLOW 1\n"
);
390
if
(!isnan(d->
_data
[d->
m
*d->
n
])) fprintf(stderr,
"BUFFER OVERFLOW 2\n"
);
391
if
(!isnan(d->
b
[d->
m
])) fprintf(stderr,
"BUFFER OVERFLOW 3\n"
);
392
if
(!isnan(d->
x
[d->
n
])) fprintf(stderr,
"BUFFER OVERFLOW 4\n"
);
393
if
(!isnan(d->
w
[d->
n
])) fprintf(stderr,
"BUFFER OVERFLOW 5\n"
);
394
if
(!isnan(d->
zz
[d->
m
])) fprintf(stderr,
"BUFFER OVERFLOW 6\n"
);
395
fprintf(stderr,
"tested buffer overflow\n"
); fflush(stderr);
396
#endif
397
398
free(d->
a
);
399
free(d->
index
);
400
free(d->
_data
);
401
// then set everything to zero or NULL again
402
nnlsqDataInit
(d);
403
}
404
/*****************************************************************************/
405
406
/*****************************************************************************/
412
int
nnlsqDataAllocate
(
414
NNLSQDATA
*d,
416
const
int
n,
418
const
int
m
419
) {
420
if
(d==NULL)
return
(
TPCERROR_FAIL
);
421
/* Delete any previous contents */
422
nnlsqDataFree
(d);
423
/* If no memory is requested, then return fail */
424
if
(n<1 || m<1)
return
(
TPCERROR_FAIL
);
425
426
/* Allocate memory for all double arrays and matrix */
427
int
s = n*m + m + n + n + m;
428
#ifdef TEST_BUFOVERFLOW
429
s+=5;
430
#endif
431
d->
_data
=(
double
*)malloc(
sizeof
(
double
)*s);
432
if
(d->
_data
==NULL)
return
(
TPCERROR_OUT_OF_MEMORY
);
433
for
(
int
i=0; i<s; i++) d->
_data
[i]=nan(
""
);
434
/* Allocate memory for matrix pointers */
435
d->
a
=(
double
**)malloc(
sizeof
(
double
*)*n);
436
if
(d->
a
==NULL) {free(d->
_data
);
return
(
TPCERROR_OUT_OF_MEMORY
);}
437
/* Set up matrix a and double vectors */
438
for
(
int
i=0; i<n; i++) d->
a
[i] = d->
_data
+ i*m;
439
d->
b
= d->
_data
+ n*m;
440
d->
x
= d->
_data
+ n*m + m;
441
d->
w
= d->
_data
+ n*m + m + n;
442
d->
zz
= d->
_data
+ n*m + m + n + n;
443
#ifdef TEST_BUFOVERFLOW
444
d->
b
++; d->
x
+=2; d->
w
+=3; d->
zz
+=4;
445
#endif
446
447
/* Allocate memory for integer array */
448
#ifdef TEST_BUFOVERFLOW
449
d->
index
=(
int
*)malloc(
sizeof
(
int
)*(1+n));
450
d->
index
[n] = 999;
451
#else
452
d->
index
=(
int
*)malloc(
sizeof
(
int
)*n);
453
#endif
454
if
(d->
index
==NULL) {free(d->
_data
); free(d->
a
);
return
(
TPCERROR_OUT_OF_MEMORY
);}
455
456
/* Set data sizes */
457
d->
n
=n;
458
d->
m
=m;
459
460
return
(
TPCERROR_OK
);
461
}
462
/*****************************************************************************/
463
464
/*****************************************************************************/
470
int
nnlsqDataCopy
(
472
NNLSQDATA
*d1,
474
NNLSQDATA
*d2
475
) {
476
if
(d1==NULL || d2==NULL || d1==d2)
return
(
TPCERROR_FAIL
);
477
if
(d1->
n
<1 || d1->
m
<1)
return
(2);
478
/* If data sizes are different then allocate memory for target */
479
if
(d1->
n
!=d2->
n
|| d1->
m
!=d2->
m
) {
480
nnlsqDataFree
(d2);
481
int
ret=
nnlsqDataAllocate
(d2, d1->
n
, d1->
m
);
482
if
(ret!=
TPCERROR_OK
)
return
(ret);
483
}
484
/* Copy contents */
485
for
(
int
ni=0; ni<d1->
n
; ni++)
486
for
(
int
mi=0; mi<d1->
m
; mi++)
487
d2->
a
[ni][mi]=d1->
a
[ni][mi];
488
for
(
int
mi=0; mi<d1->
m
; mi++)
489
d2->
b
[mi]=d1->
b
[mi];
490
for
(
int
ni=0; ni<d1->
n
; ni++)
491
d2->
x
[ni]=d1->
x
[ni];
492
for
(
int
ni=0; ni<d1->
n
; ni++)
493
d2->
w
[ni]=d1->
w
[ni];
494
for
(
int
mi=0; mi<d1->
m
; mi++)
495
d2->
zz
[mi]=d1->
zz
[mi];
496
for
(
int
ni=0; ni<d1->
n
; ni++)
497
d2->
index
[ni]=d1->
index
[ni];
498
d2->
rnorm
=d1->
rnorm
;
499
d2->
iternr
=d1->
iternr
;
500
d2->
depf
=d1->
depf
;
501
502
return
(
TPCERROR_OK
);
503
}
504
/*****************************************************************************/
505
506
/*****************************************************************************/
513
int
nnlsqDataWght
(
515
NNLSQDATA
*d,
517
double
*weight
518
) {
519
if
(d==NULL || d->
n
<1 || d->
m
<1 || d->
a
==NULL || d->
b
==NULL || weight==NULL)
return
(1);
520
521
/* Check that weights are not zero and get the square roots of them to w[] */
522
double
w[d->
m
];
523
for
(
int
mi=0; mi<d->
m
; mi++) {
524
if
(weight[mi]<=1.0e-20) w[mi]=0.0;
525
else
w[mi]=sqrt(weight[mi]);
526
}
527
528
/* Multiply rows of matrix A and elements of vector b with weights*/
529
for
(
int
mi=0; mi<d->
m
; mi++) {
530
for
(
int
ni=0; ni<d->
n
; ni++) {
531
d->
a
[ni][mi]*=w[mi];
532
}
533
d->
b
[mi]*=w[mi];
534
}
535
536
return
(0);
537
}
538
/*****************************************************************************/
539
540
/*****************************************************************************/
549
int
nnlsqDataWghtSquared
(
551
NNLSQDATA
*d,
553
double
*sweight
554
) {
555
if
(d==NULL || d->
n
<1 || d->
m
<1 || d->
a
==NULL || d->
b
==NULL || sweight==NULL)
return
(1);
556
557
/* Multiply rows of matrix A and elements of vector b with weights */
558
for
(
int
mi=0; mi<d->
m
; mi++) {
559
for
(
int
ni=0; ni<d->
n
; ni++) {
560
d->
a
[ni][mi]*=sweight[mi];
561
}
562
d->
b
[mi]*=sweight[mi];
563
}
564
565
return
(0);
566
}
567
/*****************************************************************************/
568
569
/*****************************************************************************/
nnlsqDataWghtSquared
int nnlsqDataWghtSquared(NNLSQDATA *d, double *sweight)
Definition
nnlsq.c:549
nnlsqDataWght
int nnlsqDataWght(NNLSQDATA *d, double *weight)
Definition
nnlsq.c:513
nnlsqDataFree
void nnlsqDataFree(NNLSQDATA *d)
Definition
nnlsq.c:379
nnlsqDataAllocate
int nnlsqDataAllocate(NNLSQDATA *d, const int n, const int m)
Definition
nnlsq.c:412
nnlsqDataInit
void nnlsqDataInit(NNLSQDATA *d)
Definition
nnlsq.c:358
nnlsqDataCopy
int nnlsqDataCopy(NNLSQDATA *d1, NNLSQDATA *d2)
Definition
nnlsq.c:470
nnlsq
int nnlsq(NNLSQDATA *d, int verbose)
Definition
nnlsq.c:55
NNLSQDATA
Definition
tpclinopt.h:110
NNLSQDATA::rnorm
double rnorm
Definition
tpclinopt.h:136
NNLSQDATA::x
double * x
Definition
tpclinopt.h:123
NNLSQDATA::index
int * index
Definition
tpclinopt.h:131
NNLSQDATA::b
double * b
Definition
tpclinopt.h:121
NNLSQDATA::a
double ** a
Definition
tpclinopt.h:118
NNLSQDATA::n
int n
Definition
tpclinopt.h:112
NNLSQDATA::_data
double * _data
Definition
tpclinopt.h:134
NNLSQDATA::iternr
int iternr
Definition
tpclinopt.h:139
NNLSQDATA::m
int m
Definition
tpclinopt.h:114
NNLSQDATA::zz
double * zz
Definition
tpclinopt.h:129
NNLSQDATA::depf
double depf
Definition
tpclinopt.h:141
NNLSQDATA::w
double * w
Definition
tpclinopt.h:127
tpcextensions.h
Header file for library libtpcextensions.
TPCERROR_FAIL
@ TPCERROR_FAIL
General error.
Definition
tpcextensions.h:192
TPCERROR_OUT_OF_MEMORY
@ TPCERROR_OUT_OF_MEMORY
Cannot allocate memory.
Definition
tpcextensions.h:193
TPCERROR_OK
@ TPCERROR_OK
No error.
Definition
tpcextensions.h:191
tpclinopt.h
Header file for libtpclinopt.
Generated on
for TPCCLIB by
1.17.0