TPCCLIB
Loading...
Searching...
No Matches
tpclinopt.h File Reference

Header file for libtpclinopt. More...

#include "tpcclibConfig.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "tpcextensions.h"

Go to the source code of this file.

Data Structures

struct  NNLSQDATA

Functions

int fitLine (double *x, double *y, const int n, double *m, double *c)
int fitLinePearson (double *x, double *y, const int n, double *m, double *msd, double *c, double *csd, double *d, double *dsd, double *r, double *ysd)
int highestSlope (double *x, double *y, const int n, const int slope_n, double x_start, double *m, double *yi, double *xi, double *xh)
int rootsCubic (const double a, const double b, const double c, double *x1, double *x2, double *x3)
int rootsQuadratic (const double a, const double b, const double c, double *x1, double *x2)
int qrLSQ (double **mat, double *rhs, double *sol, const unsigned int rows, const unsigned int cols, double *r2)
 QR least-squares solving routine.
int qr (double **A, int m, int n, double *B, double *X, double *rnorm, double *tau, double *res, double **wws, double *ws)
int qr_decomp (double **a, int M, int N, double *tau, double **cchain, double *chain)
int qr_solve (double **QR, int M, int N, double *tau, double *b, double *x, double *residual, double *resNorm, double **cchain, double *chain)
int qrWeight (int N, int M, double **A, double *b, double *weight, double *ws)
int qrWeightRm (int N, int M, double **A, double *b, double *weight, double *ws)
int qrSimpleLSQ (double **A, double *B, int M, int N, double *X, double *r2)
int qrLH (const unsigned int m, const unsigned int n, double *a, double *b, double *x, double *r2)
 Solve over-determined least-squares problem A x ~ b using successive Householder rotations.
double householder_transform (double *vector, int size)
int householder_hm (double tau, double *vector, double **matrix, int rowNr, int columnNr)
int householder_hv (double tau, int size, double *v, double *w)
double householder_norm (double *v, int size)
int nnls (double **a, int m, int n, double *b, double *x, double *rnorm, double *w, double *zz, int *index)
int nnlsWght (int N, int M, double **A, double *b, double *weight)
int nnlsWghtSquared (int N, int M, double **A, double *b, double *sweight)
int nnlsq (NNLSQDATA *d, int verbose)
int nnlsqWght (NNLSQDATA *d, double *weight)
int nnlsqWghtSquared (NNLSQDATA *d, double *sweight)
void nnlsqDataInit (NNLSQDATA *d)
void nnlsqDataFree (NNLSQDATA *d)
int nnlsqDataAllocate (NNLSQDATA *d, const int n, const int m)
int bvls (int key, const int m, const int n, double *a, double *b, double *bl, double *bu, double *x, double *w, double *act, double *zz, int *istate, int *iter, int verbose)
 Bounded-value least-squares method to solve the linear problem A x ~ b , subject to limit1 <= x <= limit2.
int llsqWght (int N, int M, double **A, double *a, double *b, double *weight)
int llsqWghtSquared (int N, int M, double **A, double *a, double *b, double *weight)

Detailed Description

Header file for libtpclinopt.

Header file for template library libtpclinopt.

Author
Vesa Oikonen

Definition in file tpclinopt.h.

Function Documentation

◆ bvls()

int bvls ( int key,
const int m,
const int n,
double * a,
double * b,
double * bl,
double * bu,
double * x,
double * w,
double * act,
double * zz,
int * istate,
int * iter,
int verbose )
extern

Bounded-value least-squares method to solve the linear problem A x ~ b , subject to limit1 <= x <= limit2.

This routine is based on the text and Fortran code in C.L. Lawson and R.J. Hanson, Solving Least Squares Problems, Prentice-Hall, Englewood Cliffs, New Jersey, 1974, and Fortran codes by R.L. Parker and P.B. Stark, and by J. Burkardt.

See also
nnls, qrLH, qrLSQ, llsqWghtSquared, llsqWght
Returns
Returns 0 when successful, -1 if iteration count exceeded the limit, 1 in case of invalid data or settings, and 2 if problem cannot be solved.
Parameters
keyEnter 0 to solve the problem from scratch, or <>0 to initialize the routine using caller's guess about which parameters are active within their bounds, which are at their lower bounds, and which at their upper bounds, as supplied in the array istate ('warm start'). When key <> 0, the routine initially sets the active components to the averages of their upper and lower bounds.
mNumber of samples in matrix A and the length of vector b.
nNumber of parameters in matrix A and the length of vector x. The n must not be > m unless at least n-m variables are non-active (set to their bounds).
aPointer to matrix A; matrix must be given as an n*m array, containing n consecutive m-length vectors. Contents of A are modified in this routine.
bPointer to vector b of length m. Contents of b are modified in this routine.
blArray BL[0..n-1] of lower bounds for parameters.
buArray BU[0..n-1] of upper bounds for parameters.
xPointer to the result vector x of length n.
wPointer to an array of length n, which will be used as working memory, and the minimum 2-norm || a.x-b ||, (R^2), will be written in w[0].
actPointer to an array of length m*(n+2), or m*(m+2) if m<n, which will be used as working memory.
zzPointer to an array of length m, to be used as working memory.
istatePointer to an integer array of length n+1. If parameter key <>0, then the last position istate[n] must contain the total number of components at their bounds (nbound, the bound variables'). The absolute values of the first nbound entries of istate[] are the indices of these bound' components of x[]. The sign of istate[0.. nbound-1] entries indicates whether x[|istate[i]|] is at its upper (positive) or lower (negative) bound. Entries istate[nbound..n-1] contain the indices of the active components.
iterNumber of performed iterations is returned in this variable. Maximum nr of iterations is set with this variable, or set it to 0 to use the default maximum, 3*n.
verboseVerbose level; if zero, then nothing is printed to stderr or stdout.

Definition at line 32 of file bvls.c.

78 {
79 if(verbose>0) {printf("bvls(%d, %d, %d, ...)\n", key, m, n); fflush(stdout);}
80 /* Check the input */
81 if(a==NULL || b==NULL || bl==NULL || bu==NULL || x==NULL || w==NULL ||
82 act==NULL || zz==NULL || istate==NULL || iter==NULL || n<1 || m<1)
83 {
84 if(verbose>0) fprintf(stderr, "Error: invalid input to BVLS.\n");
85 return(1);
86 }
87
88 int maxIter=*iter; if(maxIter<3) maxIter=3*n;
89 *iter=0;
90 const double eps=1.0E-13; // stopping rule
91
92 /* Step 1. Initialize everything -- active and bound sets, initial values, etc. */
93 if(verbose>1) {printf("step 1\n"); fflush(stdout);}
94
95 /* Set mm to the smaller of matrix dimensions n and m. */
96 int mm; if(m<n) mm=m; else mm=n;
97 int aindx=0; // one-based index of X[] that determined the alpha; zero means not set.
98 int aindxsign=0; // +1 if zz[aindx]> bu[aindx], -1 if zz[aindx]<bl[aindx]
99 /* istateFromStep5 is the one-based index of the parameter that most wants to be active;
100 zero value means its is currently not set. */
101 int istateFromStep5 = 0;
102
103 /* Check the consistency of given bounds bl[] and bu[]. */
104 {
105 double maxrange=0.0;
106 for(int ni=0; ni<n; ni++) {
107 double d=bu[ni]-bl[ni];
108 if(verbose>3) printf(" bounds[%d]: %g %g\n", 1+ni, bl[ni], bu[ni]);
109 if(d<0.0) {
110 if(verbose>0) fprintf(stderr, "Error: inconsistent bounds in BVLS.\n");
111 return(1);
112 }
113 maxrange=fmax(maxrange, d);
114 }
115 if(verbose>2) printf(" maxrange := %g\n", maxrange);
116 if(maxrange<1.0E-10) {
117 if(verbose>0) fprintf(stderr, "Error: no free variables in BVLS.\n");
118 return(1);
119 }
120 }
121
122 /* In a fresh initialization (key=0), bind all variables at their lower bounds.
123 If key<>0, use the supplied istate[] array to initialize the variables. */
124 int nbound, nact; // number of bound and active parameters, respectively.
125 if(key==0) {
126 nbound=n;
127 /* Write the indices; negative sign indicates lower limit */
128 /* Note that these indices must start from 1, because 0 can not have sign */
129 for(int ni=0; ni<nbound; ni++) istate[ni]=-(1+ni);
130 } else {
131 nbound=istate[n];
132 }
133 nact=n-nbound;
134 if(nact>mm) {
135 if(verbose>0) fprintf(stderr, "Error: too many active variables in BVLS starting solution.\n");
136 return(2);
137 }
138 for(int ni=0; ni<nbound; ni++) {
139 int i=abs(istate[ni])-1;
140 if(istate[ni]<0) x[i]=bl[i]; else x[i]=bu[i];
141 }
142
143 /* In a warm start (key<>0, and nbound<n) initialize the active variables to the mean of
144 their bounds. This is needed in case the initial QR results in active variables
145 out-of-bounds and Steps 8-11 get executed the first time through. */
146 for(int ni=nbound; ni<n; ni++) {
147 int i=abs(istate[ni])-1; // indices of active variables should not have signs, but let's be sure
148 x[i]=0.5*(bl[i]+bu[i]);
149 }
150
151 /* Compute bnorm, the norm of the data vector b, for reference. */
152 double bnorm=0.0;
153 for(int mi=0; mi<m; mi++) bnorm+=b[mi]*b[mi];
154 bnorm=sqrt(bnorm); if(verbose>2) printf(" initial_bnorm := %g\n", bnorm);
155
156
157 /*
158 * Main loop
159 */
160 int skipStep2=0;
161 double obj=0.0;
162 int iact=0; // The component x[iact] is the one that most wants to become active
163
164 for(*iter=1; *iter<=maxIter; ++(*iter)) {
165
166 if(verbose>1) {printf("iteration %d\n", *iter); fflush(stdout);}
167
168 if(!skipStep2) {
169 /* Step 2. */ if(verbose>1) {printf(" step 2\n"); fflush(stdout);}
170
171 /* Initialize the negative gradient vector w(*). */
172 for(int ni=0; ni<n; ni++) w[ni]=0.0;
173
174 /* Compute the residual vector b-a.x , the negative gradient vector w[*], and
175 the current objective value obj = || a.x - b ||.
176 The residual vector is stored in the mm+1'st column of act[*,*]. */
177 obj=0.0;
178 for(int mi=0; mi<m; mi++) {
179 double ri=b[mi];
180 for(int ni=0; ni<n; ni++) ri-=a[mi+ni*m]*x[ni];
181 obj+=ri*ri;
182 for(int ni=0; ni<n; ni++) w[ni]+=a[mi+ni*m]*ri;
183 act[mi+mm*m]=ri;
184 }
185 if(verbose>3) {printf(" obj := %g\n", obj); fflush(stdout);}
186
187 /* Converged? Stop if the misfit << || b ||, or if all components are active
188 (unless this is the first iteration from a 'warm start'). */
189 if((sqrt(obj)<=bnorm*eps) || ((*iter)>1 && nbound==0)) {
190 if(verbose>1) {printf("bvls converged.\n"); fflush(stdout);}
191 istate[n]=nbound;
192 w[0]=sqrt(obj);
193 return(0);
194 }
195
196 /* Add the contribution of the active components back into the residual. */
197 for(int ni=nbound; ni<n; ni++) {
198 int i=abs(istate[ni])-1;
199 for(int mi=0; mi<m; mi++) act[mi+mm*m] += a[mi+i*m]*x[i];
200 }
201 if(verbose>9) {
202 printf("Residual vector:\n");
203 for(int mi=0; mi<m; mi++) printf("\t%g", act[mi+mm*m]);
204 printf("\n");
205 }
206
207 }
208
209
210
211 /* The first iteration in a 'warm start' requires immediate QR in Step 6
212 but mostly we want go through Steps 3-5 first . */
213 if(key!=0 && (*iter)==1) {
214 if(verbose>1) printf(" 'warm start' requires immediate QR in Step 6\n");
215 } else {
216
217 int it; // variable indicating the element in istate that most wants to be active
218
219 do {
220 /* Steps 3, 4. */ if(verbose>1) {printf(" steps 3 and 4\n"); fflush(stdout);}
221 /* Find the bound element that most wants to be active. */
222 double worst=0.0;
223 it=1;
224 for(int ni=0; ni<nbound; ni++) {
225 int i=abs(istate[ni])-1;
226 double bad; if(istate[ni] < 0) bad=-w[i]; else bad=+w[i];
227 if(bad < worst) { it=ni+1; worst=bad; iact=i; }
228 }
229
230 /* Test whether the Kuhn-Tucker condition is met. */
231 if(worst>=0.0) {
232 if(verbose>1) {printf("Kuhn-Tucker condition is met.\n"); fflush(stdout);}
233 istate[n]=nbound;
234 w[0]=sqrt(obj);
235 return(0);
236 }
237
238 /* The component x[iact] is the one that most wants to become active.
239 If the last successful change in the active set was to move x[iact] to a bound,
240 don't let x[iact] in now: set the derivative of the misfit with respect to x[iact]
241 to zero and return to the Kuhn-Tucker test. */
242 if(iact==(aindx-1)) w[aindx-1]=0.0;
243 } while(iact==(aindx-1)); // Step 3 again
244
245 /* Step 5. */ if(verbose>1) {printf(" step 5\n"); fflush(stdout);}
246
247 /* Undo the effect of the new (potentially) active variable on the residual vector. */
248 if(istate[it-1]==0) { // remove this if never happening
249 if(verbose>0) fprintf(stderr, "Error: BVLS istate is zero!\n");
250 return(1);
251 }
252 {
253 double bnd;
254 if(istate[it-1]>0) bnd=bu[iact]; else bnd=bl[iact];
255 for(int mi=0; mi<m; mi++) act[mi+mm*m]+=bnd*a[mi+iact*m];
256 }
257
258 /* Set flag istateFromStep5, indicating that Step 6 was entered from Step 5.
259 This forms the basis of a test for instability: the gradient calculation shows that x[iact]
260 wants to join the active set; if QR puts x[iact] beyond the bound from which it came,
261 the gradient calculation was in error and the variable should not have been introduced. */
262 istateFromStep5=istate[it-1];
263
264 /* Swap the indices (in istate) of the new active variable and the rightmost bound variable;
265 `unbind' that location by decrementing nbound. */
266 istate[it-1]=istate[nbound-1];
267 nbound--; nact++;
268 istate[nbound]=1+iact;
269 if(mm<nact) {
270 if(verbose>0) fprintf(stderr, "Error: too many free variables in BVLS.\n");
271 return(2);
272 }
273
274 } // finalized steps 3-5
275
276 do {
277
278 skipStep2=0;
279
280 /* Step 6. */ if(verbose>1) {printf(" step 6\n"); fflush(stdout);}
281
282 /* Load array act with the appropriate columns of A for QR. For added stability, reverse
283 the column ordering so that the most recent addition to the active set is in the last
284 column. Also copy the residual vector from act[., mm] into act[., mm+1]. */
285 for(int mi=0; mi<m; mi++) {
286 act[mi+(mm+1)*m]=act[mi+mm*m]; // vector b for QR
287 for(int ni=nbound; ni<n; ni++) {
288 int i=abs(istate[ni])-1;
289 act[mi+(nact+nbound-ni-1)*m]=a[mi+i*m];
290 }
291 }
292 if(verbose>9) {
293 printf("Matrix A for QR:\n");
294 for(int ni=0; ni<nact; ni++) {
295 for(int mi=0; mi<m; mi++) printf("\t%g", act[mi+ni*nact]);
296 printf("\n");
297 }
298 printf("Vector B for QR:\n");
299 for(int mi=0; mi<m; mi++) printf("\t%g", act[(mm+1)*m + mi]);
300 printf("\n");
301 }
302
303 /* Test for linear dependence in QR, and for an instability that moves the variable
304 just introduced away from the feasible region (rather than into the region or
305 all the way through it). In either case, remove the latest vector introduced from
306 the active set and adjust the residual vector accordingly.
307 Set the gradient component (w[iact]) to zero and return to the Kuhn-Tucker test. */
308 double r2;
309 if(qrLH(m, nact, act, &act[(mm+1)*m], zz, &r2) !=0 ||
310 (istateFromStep5>0 && zz[nact-1]>bu[iact]) ||
311 (istateFromStep5<0 && zz[nact-1]<bl[iact]) )
312 {
313 nbound++;
314 if(bu[iact]>x[iact]) istate[nbound-1]=-istate[nbound-1];
315 nact--;
316 for(int mi=0; mi<m; mi++) act[mi+mm*m]-=x[iact]*a[mi+iact*m];
317 istateFromStep5 = 0; // not from step 5
318 w[iact]=0.0;
319 skipStep2=1; // we want to skip Step 2 and go directly to Step 3
320 if(verbose>3) {printf(" going from step 6 to step 3\n"); fflush(stdout);}
321 break; // go to step 3
322 }
323
324 /* If Step 6 was entered from Step 5 and we are here, a new variable has been successfully
325 introduced into the active set; the last variable that was fixed at a bound is again
326 permitted to become active. */
327 if(istateFromStep5!=0) aindx=0;
328 istateFromStep5=0;
329
330 /* Step 7. */ if(verbose>1) {printf(" step 7\n"); fflush(stdout);}
331 /* Check for strict feasibility of the new QR solution. */
332 int qr_solution_feasible=1;
333 int indexHolder=0;
334 if(verbose>8) printf(" nact=%d nbound=%d\n", nact, nbound);
335 for(int ni=0; ni<nact; ni++) {
336 indexHolder=ni; // Loop in step 8 will start from this
337 int i=abs(istate[ni+nbound])-1;
338 if(verbose>8) {
339 printf(" istate[%d]=%d\n", ni+nbound, 1+i);
340 printf(" zz[%d]=%g bl[%d]=%g bu[%d]=%g\n", nact-ni-1, zz[nact-ni-1], i, bl[i], i, bu[i]);
341 }
342 if(zz[nact-ni-1]<bl[i] || zz[nact-ni-1]>bu[i]) {
343 if(verbose>3) {printf(" new iterate is not feasible\n"); fflush(stdout);}
344 qr_solution_feasible=0; break; // go to Step 8
345 }
346 }
347 if(verbose>8) printf(" indexHolder=%d\n", indexHolder);
348 if(qr_solution_feasible) {
349 if(verbose>3) {printf(" new iterate is feasible\n"); fflush(stdout);}
350 for(int ni=0; ni<nact; ni++) {
351 int i=abs(istate[ni+nbound])-1;
352 x[i]=zz[nact-ni-1];
353 }
354 /* New iterate is feasible; back to the top. */
355 break; // Back to the start of the main loop
356 }
357
358 { // keep local variables alpha and alf local
359 double alpha=2.0;
360 /* Steps 8 and 9 */ if(verbose>1) {printf(" steps 8 and 9\n"); fflush(stdout);}
361 double alf=alpha;
362 for(int ni=indexHolder; ni<nact; ni++) {
363 int i=abs(istate[ni+nbound])-1;
364 if(zz[nact-ni-1] > bu[i]) alf=(bu[i]-x[i])/(zz[nact-ni-1]-x[i]);
365 if(zz[nact-ni-1] < bl[i]) alf=(bl[i]-x[i])/(zz[nact-ni-1]-x[i]);
366 if(alf<alpha) {
367 alpha=alf;
368 aindx=1+i;
369 if((zz[nact-ni-1]-bl[i])<0.0) aindxsign=-1; else aindxsign=+1;
370 }
371 }
372 /* Step 10 */ if(verbose>1) {printf(" step 10\n"); fflush(stdout);}
373 for(int ni=0; ni<nact; ni++) {
374 int i=abs(istate[ni+nbound])-1;
375 x[i]+=alpha*(zz[nact-ni-1]-x[i]);
376 }
377 }
378
379 /* Step 11 */ if(verbose>1) {printf(" step 11\n"); fflush(stdout);}
380 /* Move the variable that determined alpha to the appropriate bound
381 (aindx is its index; sj is + if zz[aindx]> bu[aindx], - if zz[aindx]<bl[aindx] ).
382 If any other component of x is infeasible at this stage, it must be due to round-off.
383 Bind every infeasible component and every component at a bound to the appropriate bound.
384 Correct the residual vector for any variables moved to bounds. Since at least one
385 variable is removed from the active set in this step, Loop B
386 (Steps 6-11) terminates after at most nact steps. */
387 {
388 int noldb=nbound;
389 for(int ni=0; ni<nact; ni++) {
390 int i=abs(istate[ni+noldb])-1;
391 if((bu[i]-x[i]<=0.0) || (i==(aindx-1) && aindxsign>0)) {
392 /* Move x[i] to its upper bound. */
393 x[i]=bu[i];
394 istate[ni+noldb]=istate[nbound]; istate[nbound]=+(1+i); nbound++;
395 for(int mi=0; mi<m; mi++) act[mi+mm*m]-=bu[i]*a[mi+i*m];
396 } else if( ((x[i]-bl[i])<=0.0) || (i==(aindx-1) && aindxsign<0)) {
397 /* Move x(j) to its lower bound. */
398 x[i]=bl[i];
399 istate[ni+noldb]=istate[nbound]; istate[nbound]=-(1+i); nbound++;
400 for(int mi=0; mi<m; mi++) act[mi+mm*m]-=bl[i]*a[mi+i*m];
401 }
402 }
403 nact=n-nbound;
404 }
405 /* If there are still active variables left, repeat the QR; if not, go back to step 6. */
406 } while(nact>0);
407
408 } // main loop
409
410 /* iterMax reached */
411 if(verbose>0) fprintf(stderr, "Error: BVLS fails to converge.\n");
412 return(-1);
413}
int qrLH(const unsigned int m, const unsigned int n, double *a, double *b, double *x, double *r2)
Solve over-determined least-squares problem A x ~ b using successive Householder rotations.
Definition qrlsq.c:946

◆ fitLine()

int fitLine ( double * x,
double * y,
const int n,
double * m,
double * c )
extern

Calculate regression line slope (m) and y axis intercept (c).

See also
fitLinePearson, statMeanSD, doubleMean, statSortDouble, highestSlope, linRegr3p
Returns
Returns the number of samples used in the regression, 0 in case of an error.
Parameters
xPointer to an array of x axis values. NaN's and infinite values are ignored.
yPointer to an array of y axis values. NaN's and infinite values are ignored.
nThe number of samples (length of x[] and y[]).
mPointer where calculated slope is written; enter NULL if not needed.
cPointer where calculated y axis intercept is written; enter NULL if not needed.

Definition at line 23 of file regression.c.

34 {
35 /* Check the data */
36 if(x==NULL || y==NULL) return(0);
37 if(m!=NULL) *m=nan("");
38 if(c!=NULL) *c=nan("");
39 if(n<1) return(0);
40
41 double xsum=0.0, ysum=0.0, x2sum=0.0, xysum=0.0;
42 int nn=0;
43 for(int i=0; i<n; i++) if(isfinite(x[i]) && isfinite(y[i])) {
44 xsum+=x[i]; ysum+=y[i]; x2sum+=x[i]*x[i]; xysum+=x[i]*y[i]; nn++;
45 } //printf("nn=%d\n", nn);
46 // printf("xsum=%g ysum=%g x2sum=%g xysum=%g\n", xsum, ysum, x2sum, xysum);
47 if(nn<1) return(0);
48 if(nn==1) {
49 double mm=ysum/xsum;
50 if(isfinite(mm)) {
51 if(m!=NULL) *m=mm;
52 if(c!=NULL) *c=0.0;
53 return(nn);
54 } else
55 return(0);
56 }
57 double delta=(double)nn*x2sum - xsum*xsum; //printf("delta=%g\n", delta);
58 if(delta==0.0) return(0);
59 if(m!=NULL) *m=((double)nn*xysum - xsum*ysum)/delta;
60 if(c!=NULL) *c=(x2sum*ysum - xsum*xysum)/delta;
61 return(nn);
62}

Referenced by highestSlope().

◆ fitLinePearson()

int fitLinePearson ( double * x,
double * y,
const int n,
double * m,
double * msd,
double * c,
double * csd,
double * d,
double * dsd,
double * r,
double * ysd )
extern

Calculate regression line slope (m), y axis intercept (c), their SDs, and Pearson's correlation coefficient (r).

See also
fitLine, statMeanSD, doubleMean, statSortDouble
Returns
Returns the number of samples used in the regression, 0 in case of an error.
Todo
Check SD of x axis intercept against some other program.
Parameters
xPointer to an array of x axis values. NaN's and infinite values are ignored.
yPointer to an array of y axis values. NaN's and infinite values are ignored.
nThe number of samples (length of x[] and y[]).
mPointer where calculated slope is written; enter NULL if not needed.
msdPointer where SD of slope is written; enter NULL if not needed.
cPointer where calculated y axis intercept is written; enter NULL if not needed.
csdPointer where SD of y axis intercept is written; enter NULL if not needed.
dPointer where calculated x axis intercept is written; enter NULL if not needed.
dsdPointer where SD of x axis intercept is written; enter NULL if not needed.
rPointer where Pearson's correlation coefficient is written; enter NULL if not needed.
ysdPointer where residual variance of y values is written; enter NULL if not needed.

Definition at line 72 of file regression.c.

95 {
96 /* Check the data */
97 if(x==NULL || y==NULL) return(0);
98 if(m!=NULL) *m=nan("");
99 if(c!=NULL) *c=nan("");
100 if(d!=NULL) *d=nan("");
101 if(msd!=NULL) *msd=nan("");
102 if(csd!=NULL) *csd=nan("");
103 if(dsd!=NULL) *dsd=nan("");
104 if(r!=NULL) *r=nan("");
105 if(ysd!=NULL) *ysd=nan("");
106 if(n<1) return(0);
107
108 double xsum=0.0, ysum=0.0, x2sum=0.0, y2sum=0.0, xysum=0.0;
109 int nn=0;
110 for(int i=0; i<n; i++) if(isfinite(x[i]) && isfinite(y[i])) {
111 xsum+=x[i]; ysum+=y[i]; x2sum+=x[i]*x[i]; y2sum+=y[i]*y[i]; xysum+=x[i]*y[i]; nn++;
112 }
113 if(nn<1) return(0);
114 if(nn==1) {
115 double mm=ysum/xsum;
116 if(isfinite(mm)) {
117 if(m!=NULL) *m=mm;
118 if(c!=NULL) *c=0.0;
119 if(d!=NULL) {*d=0.0; if(fabs(mm)<1.0E-10) *d=nan("");}
120 if(msd!=NULL) *msd=0.0;
121 if(csd!=NULL) *csd=0.0;
122 if(dsd!=NULL) {*dsd=0.0; if(fabs(mm)<1.0E-10) *dsd=nan("");}
123 if(r!=NULL) *r=1.0;
124 if(ysd!=NULL) *ysd=0.0;
125 return(nn);
126 } else
127 return(0);
128 }
129 double xmean=xsum/(double)nn;
130 double ymean=xsum/(double)nn;
131 double dx2sum=0.0, /*dy2sum=0.0,*/ dxdysum=0.0;
132 for(int i=0; i<n; i++) if(isfinite(x[i]) && isfinite(y[i])) {
133 double f=x[i]-xmean; dx2sum+=f*f;
134 double g=y[i]-ymean; /*dy2sum+=g*g;*/
135 dxdysum+=f*g;
136 }
137 // slope and intercept
138 double slope=dxdysum/dx2sum;
139 double ic=(dx2sum*ysum - xsum*dxdysum)/((double)nn*dx2sum);
140 if(!isfinite(slope) || !isfinite(ic)) return(0);
141 if(m!=NULL) *m=slope;
142 if(c!=NULL) *c=ic;
143 double xic=-ic/slope; if(!isfinite(xic)) xic=nan("");
144 if(d!=NULL) *d=xic;
145 // Errors
146 double ry2sum=0.0;
147 for(int i=0; i<n; i++) if(isfinite(x[i]) && isfinite(y[i])) {
148 double f=slope*x[i]+ic-y[i];
149 ry2sum+=f*f;
150 }
151 double ye=sqrt(ry2sum/(double)(nn-2)); if(!isfinite(ye)) ye=0.0;
152 if(ysd!=NULL) *ysd=ye;
153 double slopee=ye/sqrt(dx2sum); if(!isfinite(slopee)) slopee=0.0;
154 double ice=ye/sqrt((double)nn-xsum*xsum/x2sum); if(!isfinite(ice)) ice=0.0;
155 if(msd!=NULL) *msd=slopee;
156 if(csd!=NULL) *csd=ice;
157 if(dsd!=NULL) { // SD of x axis intercept
158 double xice=fabs(ye/slope)*sqrt((1.0/(double)nn) + ymean*ymean/(slope*slope*dx2sum));
159 if(!isfinite(xice)) xice=nan("");
160 *dsd=xice;
161 }
162 // Pearson's correlation coefficient
163 double rr=(xysum-((xsum*ysum)/(double)nn)) /
164 sqrt((x2sum-xsum*xsum/(double)nn)*(y2sum-ysum*ysum/(double)nn));
165 // and correct for small sample size
166 if(nn>4) rr*=1.0+(1.0-rr*rr)/(double)(2*(nn-4));
167 if(!isfinite(rr)) rr=0.0; else rr=fabs(rr);
168 if(r!=NULL) *r=rr;
169
170 return(nn);
171}

◆ highestSlope()

int highestSlope ( double * x,
double * y,
const int n,
const int slope_n,
double x_start,
double * m,
double * yi,
double * xi,
double * xh )
extern

Find the regression line with the highest slope for x,y data.

See also
fitLine
Returns
Return 0 if no errors were found.
Parameters
xPointer to an array of x axis values. NaN's and infinite values are ignored. Data must be sorted by increasing x, and overlapping x values may cause problem.
yPointer to an array of y axis values. NaN's and infinite values are ignored. Data is not modified.
nThe number of samples (length of x[] and y[]).
slope_nThe number of samples used to fit the line; must be at least 2.
x_startEstimation start x value, samples with smaller x are ignored; can usually be set to zero.
mPointer where calculated max slope is written; NULL if not needed.
yiPointer where calculated y axis intercept is written; NULL if not needed.
xiPointer where calculated x axis intercept is written; NULL if not needed. This could be used as an estimate of radioactivity appearance time in TAC data, but you must then check that the max slope m is positive.
xhPointer where the place (x) of the highest slope is written; NULL if not needed.

Definition at line 179 of file regression.c.

202 {
203 /* Check the data */
204 if(x==NULL || y==NULL || n<2 || slope_n<2) return(1);
205 if(m!=NULL) *m=nan("");
206 if(yi!=NULL) *yi=nan("");
207 if(xi!=NULL) *xi=nan("");
208 if(xh!=NULL) *xh=nan("");
209
210 /* Make copy of original data */
211 double xx[n], yy[n]; int nn=0;
212 for(int i=0; i<n; i++)
213 if(isfinite(x[i]) && isfinite(y[i])) {
214 if(isfinite(x_start) && x[i]<x_start) continue;
215 xx[nn]=x[i]; yy[nn]=y[i]; nn++;
216 }
217 if(nn<slope_n) return(2);
218
219 /* Compute regression lines */
220 double max_slope=nan(""), ic_at_max=nan(""), slope, ic;
221 int i_at_max=0;
222 for(int i=0; i<=nn-slope_n; i++) {
223 if(fitLine(xx+i, yy+i, slope_n, &slope, &ic)<slope_n) continue;
224 if(!isfinite(slope) || !isfinite(ic)) continue;
225 if(isnan(max_slope) || slope>max_slope) {
226 max_slope=slope; ic_at_max=ic; i_at_max=i;
227 }
228 }
229 if(!isfinite(max_slope)) return(3);
230 if(m!=NULL) *m=max_slope;
231 if(yi!=NULL) *yi=ic_at_max;
232 if(xi!=NULL) {if(max_slope!=0.0) *xi=-ic_at_max/max_slope;}
233 if(xh!=NULL) {
234 *xh=0.0; for(int i=i_at_max; i<i_at_max+slope_n; i++) *xh+=xx[i];
235 *xh/=(double)slope_n;
236 }
237
238 return(0);
239}
int fitLine(double *x, double *y, const int n, double *m, double *c)
Definition regression.c:23

◆ householder_hm()

int householder_hm ( double tau,
double * vector,
double ** matrix,
int rowNr,
int columnNr )
extern

Applies a householder transformation defined by vector "vector" and scalar tau to the left-hand side of the matrix. (I - tau vector vector^T)*matrix The result of the transform is stored in matrix.

Returns
Returns 0 if ok.
Parameters
tauCoefficient defining householder transform.
vectorVector defining householder transform (of size rowNr).
matrixthe matrix that is to be transformed.
rowNrNr of rows in matrix.
columnNrNr of columns in matrix.

Definition at line 87 of file hholder.c.

98 {
99 int i, j;
100 double wj;
101
102 if(tau==0.0) return(0); // success
103 if(rowNr<1 || columnNr<1) return(1);
104 for(j=0; j<columnNr; j++) {
105 /* Compute wj = vk Akj */
106 wj=matrix[0][j];
107 for(i=1; i<rowNr; i++) /* note, computed for v(0) = 1 above */
108 wj += vector[i]*matrix[i][j];
109 /* Aij = Aij - tau vi wj */
110 /* i = 0 */
111 matrix[0][j]-=tau*wj;
112 /* i = 1 .. M-1 */
113 for(i=1; i<rowNr; i++) matrix[i][j]-=tau*vector[i]*wj;
114 }
115 return(0);
116}

Referenced by qr_decomp().

◆ householder_hv()

int householder_hv ( double tau,
int size,
double * v,
double * w )
extern

Applies a householder transformation defined by vector v and coefficient tau to vector w w = (I - tau v v^T) w.

Returns
Returns 0 if ok.
Parameters
tauCoefficient defining householder transform.
sizeSize of vectors v and w.
vVector v.
wVector w.

Definition at line 126 of file hholder.c.

135 {
136 int i;
137 double d;
138
139 if(tau==0) return(0); // success
140 if(size<1) return(1);
141 /* d = v'w */
142 d=w[0]; for(i=1; i<size; i++) d+=v[i]*w[i];
143 /* w = w - tau (v) (v'w) */
144 w[0]-=tau*d;
145 for(i=1; i<size; i++) w[i]-=tau*v[i]*d;
146 return(0);
147}

◆ householder_norm()

double householder_norm ( double * v,
int size )
extern

Calculates the euclidean norm of vector v[].

Returns
Returns the euclidean norm of a vector.
Parameters
vVector v.
sizeSize of vector v[].

Definition at line 155 of file hholder.c.

160 {
161 double ss=0.0;
162 int i;
163
164 for(i=0; i<size; i++) ss+=v[i]*v[i];
165 return sqrt(ss);
166}

◆ householder_transform()

double householder_transform ( double * v,
int N )
extern

This function prepares a Householder transformation P = I - tau h h^T which can be used to zero all the elements of the input vector except the first one that will get value beta. On output the elements 1 - size-1 of the vector h are stored in locations vector[1] - vector[size-1] of the input vector and value of beta is stored in location vector[0].

Returns
The scalar tau is returned.
Parameters
vThe N-vector to be transformed.
Nsize of the vector.

Definition at line 33 of file hholder.c.

38 {
39 double vnorm, alpha, beta, tau;
40 int n;
41
42 if(N<1) return 0.0; // tau = 0
43 /* Euclidean norm of the vector starting from the second value */
44 vnorm=0.0; for(n=1; n<N; n++) vnorm+=v[n]*v[n];
45 vnorm=sqrt(vnorm); if(isnan(vnorm) || vnorm==0.0) return 0.0; // tau = 0
46
47 /* Computing the coefficient tau */
48 alpha=v[0];
49 beta= - (alpha >= 0.0 ? +1.0 : -1.0) * hypot(alpha, vnorm);
50 tau=(beta-alpha)/beta ;
51
52 /* Scale the Householder vector so that the first element will be 1.
53 * (Scaling is also affecting the coefficient tau).
54 * Without scaling, the first element would have value (alpha - beta). */
55#if(0) // Kaisa's version
56 {
57 double os=1.0/(alpha-beta);
58 for(n=1; n<N; n++) v[n]*=os;
59 v[0]=beta;
60 }
61#else // Vesa's version
62 {
63 double s=alpha-beta;
64 if(fabs(s)>DBL_MIN) {
65 v[0]=beta;
66 for(n=1; n<N; n++) v[n]*=(1.0/s);
67 } else {
68 v[0]=beta;
69 for(n=1; n<N; n++) v[n]*=(doubleMachEps()/s);
70 for(n=1; n<N; n++) v[n]*=(1.0/doubleMachEps());
71 }
72 }
73#endif
74
75 return tau;
76}
double doubleMachEps()
Definition doubleutil.c:105

Referenced by qr_decomp().

◆ llsqWght()

int llsqWght ( int N,
int M,
double ** A,
double * a,
double * b,
double * weight )
extern

Algorithm for weighting the problem that is given to a LLSQ algorithm.

Square roots of weights are used because in LLSQ algorithms the difference w*A-w*b is squared.

See also
bvls, llsqWghtSquared, nnlsWghtSquared
Returns
Algorithm returns zero if successful, 1 if arguments are inappropriate.
Parameters
NMatrix A dimension N (nr of parameters).
MMatrix A dimension M (nr of samples).
APointer to matrix A[N][M]; enter NULL to use following matrix format instead.
aPointer to matrix A[N*M]; enter NULL to use previous matrix format instead.
bVector B of length M.
weightWeights for each sample (array of length M).

Definition at line 425 of file bvls.c.

438 {
439 int n, m;
440 double *w;
441
442 /* Check the arguments */
443 if(N<1 || M<1 || (A==NULL && a==NULL) || b==NULL || weight==NULL) return(1);
444
445 /* Allocate memory */
446 w=(double*)malloc(M*sizeof(double)); if(w==NULL) return(2);
447
448 /* Check that weights are not zero and get the square roots of them to w[] */
449 for(m=0; m<M; m++) {
450 if(weight[m]<=1.0e-20) w[m]=0.0;
451 else w[m]=sqrt(weight[m]);
452 }
453
454 /* Multiply rows of matrix A and elements of vector b with weights*/
455 for(m=0; m<M; m++) {
456 for(n=0; n<N; n++) {
457 if(A!=NULL) A[n][m]*=w[m];
458 if(a!=NULL) a[m+n*M]*=w[m];
459 }
460 b[m]*=w[m];
461 }
462
463 free(w);
464 return(0);
465}

◆ llsqWghtSquared()

int llsqWghtSquared ( int N,
int M,
double ** A,
double * a,
double * b,
double * sweight )
extern

Algorithm for weighting the problem that is given to a LLSQ algorithm.

Square roots of weights are used because in LLSQ algorithms the difference w*A-w*b is squared.

Here user must give squared weights; this makes calculation faster, when this function needs to be called many times.

See also
llsqWght, bvls
Returns
Algorithm returns zero if successful, 1 if arguments are inappropriate.
Parameters
NMatrix A dimension N (nr of parameters).
MMatrix A dimension M (nr of samples).
APointer to matrix A[N][M]; enter NULL to use following matrix format instead.
aPointer to matrix A[N*M]; enter NULL to use previous matrix format instead.
bVector B of length M.
sweightSquared weights for each sample (array of length M).

Definition at line 480 of file bvls.c.

493 {
494 int n, m;
495
496 /* Check the arguments */
497 if(N<1 || M<1 || (A==NULL && a==NULL) || b==NULL || sweight==NULL) return(1);
498
499 /* Multiply rows of matrix A and elements of vector b with weights*/
500 for(m=0; m<M; m++) {
501 for(n=0; n<N; n++) {
502 if(A!=NULL) A[n][m]*=sweight[m];
503 if(a!=NULL) a[m+n*M]*=sweight[m];
504 }
505 b[m]*=sweight[m];
506 }
507
508 return(0);
509}

◆ nnls()

int nnls ( double ** a,
int m,
int n,
double * b,
double * x,
double * rnorm,
double * wp,
double * zzp,
int * indexp )
extern

Algorithm NNLS (Non-negative least-squares).

Given an m by n matrix A, and an m-vector B, computes an n-vector X, that solves the least squares problem A * X = B , subject to X>=0

Instead of pointers for working space, NULL can be given to let this function to allocate and free the required memory.

See also
qrLSQ, nnlsWghtSquared
Returns
Function returns 0 if successful, 1, if iteration count exceeded 3*N, or 2 in case of invalid problem dimensions or memory allocation error.
Parameters
aOn entry, a[ 0... N ][ 0 ... M ] contains the M by N matrix A. On exit, a[][] contains the product matrix Q*A, where Q is an m by n orthogonal matrix generated implicitly by this function.
mMatrix dimension m.
nMatrix dimension n.
bOn entry, b[] must contain the m-vector B. On exit, b[] contains Q*B.
xOn exit, x[] will contain the solution vector.
rnormOn exit, rnorm contains the squared Euclidean norm of the residual vector, R^2 (Sum-of-Squares). If NULL is given, no rnorm is calculated.
wpAn n-array of working space, wp[]. On exit, wp[] will contain the dual solution vector. wp[i]=0.0 for all i in set p and wp[i]<=0.0 for all i in set z. Can be NULL, which causes this algorithm to allocate memory for it.
zzpAn m-array of working space, zz[]. Can be NULL, which causes this algorithm to allocate memory for it.
indexpAn n-array of working space, index[]. Can be NULL, which causes this algorithm to allocate memory for it.

Definition at line 43 of file nnls.c.

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 */

Referenced by spectralDExp(), spectralDMSurge(), and tacDelayCMFit().

◆ nnlsq()

int nnlsq ( NNLSQDATA * d,
int verbose )
extern

Algorithm NNLS (Non-negative least-squares).

The same algorithm as nnls(), but this one gets its data in a struct, and max iteration number and dependence factor (previously fixed to 0.01) can be set as function parameters in the struct.

Given an m by n matrix A, and an m-vector B, computes an n-vector X, that solves the least squares problem A * X = B , subject to X>=0

Instead of pointers for working space, NULL can be given to let this function to allocate and free the required memory.

See also
nnlsqDataInit, nnlsqDataAllocate, nnlsqDataFree, nnlsqWghtSquared, nnls, qrLSQ
Returns
Function returns 0 if successful, 1, if iteration count exceeded specified limit, 2 in case of invalid problem dimensions, and >2 in case of other errors.
Parameters
dPointer to structure containing the data and place for the results.
Precondition
Initiate the structure, allocate memory for the data, and possibly weight the data.
Postcondition
Free the allocated memory.
See also
nnlsqDataInit, nnlsqDataAllocate, nnlsqDataFree
Parameters
verboseVerbose level; if zero, then nothing is printed to stderr or stdout.

Definition at line 55 of file nnlsq.c.

64 {
65 if(verbose>0) {printf("%s()\n", __func__); fflush(stdout);}
66
67 /* Check the data */
68 if(d==NULL || d->m<1 || d->n<1 || d->a==NULL || d->b==NULL ||
69 d->x==NULL || d->w==NULL || d->zz==NULL || d->index==NULL)
70 return(2);
71 if(d->depf<1.0E-08 || d->depf>0.5) return(3);
72
73 /* Initialize */
74 for(int ni=0; ni<d->n; ni++) d->x[ni]=0.0;
75 for(int ni=0; ni<d->n; ni++) d->index[ni]=ni;
76 d->rnorm=nan("");
77 int iz1=0;
78 int iz2=d->n-1;
79 int nsetp=0;
80 int npp1=0;
81
82
83 /* Main loop; quit if all coefficients are already in the solution or
84 if M cols of A have been triangulated */
85 double up=0.0;
86 int itermax, iter=0;
87 if(d->iternr>=3) itermax=d->iternr; else itermax=3*d->n;
88 int j=0, jj=0;
89 while(iz1<=iz2 && nsetp<d->m) {
90 /* Compute components of the dual (negative gradient) vector W[] */
91 for(int iz=iz1; iz<=iz2; iz++) {
92 int ni=d->index[iz];
93 double sm=0.;
94 for(int mi=npp1; mi<d->m; mi++) sm+=d->a[ni][mi]*d->b[mi];
95 d->w[ni]=sm;
96 }
97
98 double wmax;
99 int izmax=0;
100 while(1) {
101
102 /* Find largest positive W */
103 wmax=0.0;
104 for(int iz=iz1; iz<=iz2; iz++) {
105 int i=d->index[iz];
106 if(d->w[i]>wmax) {wmax=d->w[i]; izmax=iz;}
107 }
108
109 /* Terminate if wmax<=0.; it indicates satisfaction of the Kuhn-Tucker conditions */
110 if(wmax<=0.0) break;
111
112 /* The sign of W[j] is ok for j to be moved to set P.
113 Begin the transformation and check new diagonal element to avoid near linear dependence. */
114 j=d->index[izmax];
115 double asave=d->a[j][npp1];
116// up=0.0;
117 if(nnlsq_lss_h12(1, npp1, npp1+1, d->m, d->a[j], &up, NULL)) return(2);
118 double unorm=0.0;
119 if(nsetp!=0) for(int mi=0; mi<nsetp; mi++) unorm+=d->a[j][mi]*d->a[j][mi];
120 unorm=sqrt(unorm);
121 double e=unorm+fabs(d->a[j][npp1])*d->depf;
122 if((e-unorm)>0.0) {
123 /* Col j is sufficiently independent. Copy B into ZZ, update ZZ
124 and solve for ztest ( = proposed new value for X[j] ) */
125 for(int mi=0; mi<d->m; mi++) d->zz[mi]=d->b[mi];
126 nnlsq_lss_h12(2, npp1, npp1+1, d->m, d->a[j], &up, d->zz);
127 double ztest=d->zz[npp1]/d->a[j][npp1];
128 /* See if ztest is positive */
129 if(ztest>0.) break;
130 }
131
132 /* Reject j as a candidate to be moved from set Z to set P. Restore
133 A[npp1,j], set W[j]=0., and loop back to test dual coefficients again */
134 d->a[j][npp1]=asave; d->w[j]=0.;
135 } /* while(1) */
136 if(wmax<=0.0) break;
137
138 /* Index j=INDEX[izmax] has been selected to be moved from set Z to set P.
139 Update B and indices, apply householder transformations to cols in
140 new set Z, zero sub-diagonal elements in col j, set W[j]=0. */
141 for(int mi=0; mi<d->m; mi++) d->b[mi]=d->zz[mi];
142 d->index[izmax]=d->index[iz1]; d->index[iz1]=j; iz1++; nsetp=npp1+1; npp1++;
143 if(iz1<=iz2)
144 for(int jz=iz1; jz<=iz2; jz++) {
145 jj=d->index[jz];
146 nnlsq_lss_h12(2, nsetp-1, npp1, d->m, d->a[j], &up, d->a[jj]);
147 }
148 if(nsetp!=d->m) for(int mi=npp1; mi<d->m; mi++) d->a[j][mi]=0.;
149 d->w[j]=0.;
150
151 /* Solve the triangular system; store the solution temporarily in Z[] */
152 for(int mi=0; mi<nsetp; mi++) {
153 int ip=nsetp-(mi+1);
154 if(mi!=0) for(int ii=0; ii<=ip; ii++) d->zz[ii]-=d->a[jj][ii]*d->zz[ip+1];
155 jj=d->index[ip]; d->zz[ip]/=d->a[jj][ip];
156 }
157
158 /* Secondary loop begins here */
159 while(++iter<itermax) {
160 /* See if all new constrained coefficients are feasible; if not, compute alpha */
161 double alpha=2.0;
162 for(int ip=0; ip<nsetp; ip++) {
163 int ni=d->index[ip];
164 if(d->zz[ip]<=0.) {
165 double t=-d->x[ni]/(d->zz[ip]-d->x[ni]);
166 if(alpha>t) {alpha=t; jj=ip-1;}
167 }
168 }
169
170 /* If all new constrained coefficients are feasible then still alpha==2.
171 If so, then exit from the secondary loop to main loop */
172 if(alpha==2.0) break;
173
174 /* Use alpha (0.<alpha<1.) to interpolate between old X and new ZZ */
175 for(int ip=0; ip<nsetp; ip++) {
176 int ni=d->index[ip]; d->x[ni]+=alpha*(d->zz[ip]-d->x[ni]);
177 }
178
179 /* Modify A and B and the INDEX arrays to move coefficient i from set P to set Z. */
180 int pfeas=1;
181 int k=d->index[jj+1];
182 do {
183 d->x[k]=0.;
184 if(jj!=(nsetp-1)) {
185 jj++;
186 for(int ni=jj+1; ni<nsetp; ni++) {
187 int ii=d->index[ni]; d->index[ni-1]=ii;
188 double ss, cc;
189 nnlsq_lss_g1(d->a[ii][ni-1], d->a[ii][ni], &cc, &ss, &d->a[ii][ni-1]);
190 d->a[ii][ni]=0.0;
191 for(int nj=0; nj<d->n; nj++) if(nj!=ii) {
192 /* Apply procedure G2 (CC,SS,A(J-1,L),A(J,L)) */
193 double temp=d->a[nj][ni-1];
194 d->a[nj][ni-1]=cc*temp+ss*d->a[nj][ni];
195 d->a[nj][ni]=-ss*temp+cc*d->a[nj][ni];
196 }
197 /* Apply procedure G2 (CC,SS,B(J-1),B(J)) */
198 double temp=d->b[ni-1];
199 d->b[ni-1]=cc*temp+ss*d->b[ni];
200 d->b[ni]=-ss*temp+cc*d->b[ni];
201 }
202 }
203 npp1=nsetp-1; nsetp--; iz1--; d->index[iz1]=k;
204
205 /* See if the remaining coefficients in set P are feasible; they should be because of
206 the way alpha was determined. If any are infeasible it is due to round-off error.
207 Any that are non-positive will be set to zero and moved from set P to set Z. */
208 pfeas=1;
209 for(jj=0; jj<nsetp; jj++) {
210 k=d->index[jj]; if(d->x[k]<=0.) {pfeas=0; break;}
211 }
212 } while(pfeas==0);
213
214 /* Copy B[] into zz[], then solve again and loop back */
215 for(int mi=0; mi<d->m; mi++) d->zz[mi]=d->b[mi];
216 for(int mi=0; mi<nsetp; mi++) {
217 int ip=nsetp-(mi+1);
218 if(mi!=0) for(int ii=0; ii<=ip; ii++) d->zz[ii]-=d->a[jj][ii]*d->zz[ip+1];
219 jj=d->index[ip]; d->zz[ip]/=d->a[jj][ip];
220 }
221 } /* end of secondary loop */
222
223 if(iter>=itermax) break;
224 for(int ip=0; ip<nsetp; ip++) {int k=d->index[ip]; d->x[k]=d->zz[ip];}
225 } /* end of main loop */
226
227 if(npp1>=d->m) for(int ni=0; ni<d->n; ni++) d->w[ni]=0.;
228
229 /* Compute the norm of the final residual vector (sum-of-squares) */
230 d->rnorm=0.0;
231 for(int mi=npp1; mi<d->m; mi++) d->rnorm+=(d->b[mi]*d->b[mi]);
232
233 d->iternr=iter;
234 if(verbose>2) printf(" %d iterations.\n", iter);
235 if(iter>=itermax) {
236 if(verbose>1) printf(" max iterations reached.\n");
237 return(1);
238 }
239 return(0);
240} /* nnlsq */
double rnorm
Definition tpclinopt.h:136
double * x
Definition tpclinopt.h:123
int * index
Definition tpclinopt.h:131
double * b
Definition tpclinopt.h:121
double ** a
Definition tpclinopt.h:118
double * zz
Definition tpclinopt.h:129
double depf
Definition tpclinopt.h:141
double * w
Definition tpclinopt.h:127

◆ nnlsqDataAllocate()

int nnlsqDataAllocate ( NNLSQDATA * d,
const int n,
const int m )
extern

Allocate memory for NNLSQDATA (and set data pointers inside the structure). Any previous contents are deleted. Contents are set to NaN or zero.

See also
nnlsDataInit, nnlsqDataFree, nnlsq, nnlsqWght
Returns
Returns TPCERROR status (0 when successful).
Parameters
dPointer to initiated structure; any old contents are deleted.
nNumber of parameters (columns of matrix A).
mNumber of samples (rows of matrix A).

Definition at line 411 of file nnlsq.c.

418 {
419 if(d==NULL) return(TPCERROR_FAIL);
420 /* Delete any previous contents */
421 nnlsqDataFree(d);
422 /* If no memory is requested, then return fail */
423 if(n<1 || m<1) return(TPCERROR_FAIL);
424
425 /* Allocate memory for all double arrays and matrix */
426 int s = n*m + m + n + n + m;
427#ifdef TEST_BUFOVERFLOW
428 s+=5;
429#endif
430 d->_data=(double*)malloc(sizeof(double)*s);
431 if(d->_data==NULL) return(TPCERROR_OUT_OF_MEMORY);
432 for(int i=0; i<s; i++) d->_data[i]=nan("");
433 /* Allocate memory for matrix pointers */
434 d->a=(double**)malloc(sizeof(double*)*n);
435 if(d->a==NULL) {free(d->_data); return(TPCERROR_OUT_OF_MEMORY);}
436 /* Set up matrix a and double vectors */
437 for(int i=0; i<n; i++) d->a[i] = d->_data + i*m;
438 d->b = d->_data + n*m;
439 d->x = d->_data + n*m + m;
440 d->w = d->_data + n*m + m + n;
441 d->zz = d->_data + n*m + m + n + n;
442#ifdef TEST_BUFOVERFLOW
443 d->b++; d->x+=2; d->w+=3; d->zz+=4;
444#endif
445
446 /* Allocate memory for integer array */
447#ifdef TEST_BUFOVERFLOW
448 d->index=(int*)malloc(sizeof(int)*(1+n));
449 d->index[n] = 999;
450#else
451 d->index=(int*)malloc(sizeof(int)*n);
452#endif
453 if(d->index==NULL) {free(d->_data); free(d->a); return(TPCERROR_OUT_OF_MEMORY);}
454
455 /* Set data sizes */
456 d->n=n;
457 d->m=m;
458
459 return(TPCERROR_OK);
460}
void nnlsqDataFree(NNLSQDATA *d)
Definition nnlsq.c:378
double * _data
Definition tpclinopt.h:134
@ TPCERROR_FAIL
General error.
@ TPCERROR_OUT_OF_MEMORY
Cannot allocate memory.
@ TPCERROR_OK
No error.

◆ nnlsqDataFree()

void nnlsqDataFree ( NNLSQDATA * d)
extern

Free memory allocated for NNLSQDATA data. All contents are destroyed.

Precondition
Before first use initialize the structure with nnlsqDataInit().
See also
nnlsqDataInit, nnlsqDataAllocate
Author
Vesa Oikonen
Parameters
dPointer to structure.

Definition at line 378 of file nnlsq.c.

381 {
382 if(d==NULL) return;
383 if(d->n<1) return;
384 if(d->m<1) return;
385
386#ifdef TEST_BUFOVERFLOW
387 fprintf(stderr, "testing if buffer overflow happened\n"); fflush(stderr);
388 if(d->index[d->n]!=999) fprintf(stderr, "BUFFER OVERFLOW 1\n");
389 if(!isnan(d->_data[d->m*d->n])) fprintf(stderr, "BUFFER OVERFLOW 2\n");
390 if(!isnan(d->b[d->m])) fprintf(stderr, "BUFFER OVERFLOW 3\n");
391 if(!isnan(d->x[d->n])) fprintf(stderr, "BUFFER OVERFLOW 4\n");
392 if(!isnan(d->w[d->n])) fprintf(stderr, "BUFFER OVERFLOW 5\n");
393 if(!isnan(d->zz[d->m])) fprintf(stderr, "BUFFER OVERFLOW 6\n");
394 fprintf(stderr, "tested buffer overflow\n"); fflush(stderr);
395#endif
396
397 free(d->a);
398 free(d->index);
399 free(d->_data);
400 // then set everything to zero or NULL again
401 nnlsqDataInit(d);
402}
void nnlsqDataInit(NNLSQDATA *d)
Definition nnlsq.c:357

Referenced by nnlsqDataAllocate().

◆ nnlsqDataInit()

void nnlsqDataInit ( NNLSQDATA * d)
extern

Initiate the NNLSQDATA structure before any use.

See also
nnlsqDataFree, nnlsqDataAllocate, nnlsq, nnlsqWght
Author
Vesa Oikonen
Parameters
dPointer to structure to initiate before use.

Definition at line 357 of file nnlsq.c.

360 {
361 if(d==NULL) return;
362 d->n = d->m = 0;
363 d->a = NULL;
364 d->b = d->x = d->w = d->zz = d->_data = NULL;
365 d->index = NULL;
366 d->rnorm = 0.0;
367 d->iternr = 0;
368 d->depf = 0.01; // default
369}

Referenced by nnlsqDataFree().

◆ nnlsqWght()

int nnlsqWght ( NNLSQDATA * d,
double * weight )
extern

Algorithm for weighting the problem that is given to NNLS-algorithm.

Square roots of weights are used because in NNLS the difference w*A-w*b is squared.

Returns
Algorithm returns zero if successful, 1 if arguments are inappropriate.
See also
nnlsqWghtSquared, nnlsq, llsqWght
Parameters
dPointer to filled data structure.
weightWeights for each sample (array of length M).

Definition at line 470 of file nnlsq.c.

475 {
476 if(d==NULL || d->n<1 || d->m<1 || d->a==NULL || d->b==NULL || weight==NULL) return(1);
477
478 /* Check that weights are not zero and get the square roots of them to w[] */
479 double w[d->m];
480 for(int mi=0; mi<d->m; mi++) {
481 if(weight[mi]<=1.0e-20) w[mi]=0.0;
482 else w[mi]=sqrt(weight[mi]);
483 }
484
485 /* Multiply rows of matrix A and elements of vector b with weights*/
486 for(int mi=0; mi<d->m; mi++) {
487 for(int ni=0; ni<d->n; ni++) {
488 d->a[ni][mi]*=w[mi];
489 }
490 d->b[mi]*=w[mi];
491 }
492
493 return(0);
494}

◆ nnlsqWghtSquared()

int nnlsqWghtSquared ( NNLSQDATA * d,
double * sweight )
extern

Algorithm for weighting the problem that is given to NNLS-algorithm.

Square roots of weights are used because in NNLS the difference w*A-w*b is squared. Here user must give squared weights; this makes calculation faster, when this function needs to be called many times.

Returns
Algorithm returns zero if successful, 1 if arguments are inappropriate.
See also
nnlsqWght, nnlsq
Parameters
dPointer to filled data structure.
sweightSquared weights for each sample (array of length d->m).

Definition at line 506 of file nnlsq.c.

511 {
512 if(d==NULL || d->n<1 || d->m<1 || d->a==NULL || d->b==NULL || sweight==NULL) return(1);
513
514 /* Multiply rows of matrix A and elements of vector b with weights */
515 for(int mi=0; mi<d->m; mi++) {
516 for(int ni=0; ni<d->n; ni++) {
517 d->a[ni][mi]*=sweight[mi];
518 }
519 d->b[mi]*=sweight[mi];
520 }
521
522 return(0);
523}

◆ nnlsWght()

int nnlsWght ( int N,
int M,
double ** A,
double * b,
double * weight )
extern

Algorithm for weighting the problem that is given to nnls-algorithm.

Square roots of weights are used because in nnls the difference w*A-w*b is squared.

Returns
Algorithm returns zero if successful, 1 if arguments are inappropriate.
See also
nnlsWghtSquared, nnls, qrLSQ, llsqWght
Parameters
NNNLS dimension N (nr of parameters).
MNNLS dimension M (nr of samples).
ANNLS matrix A.
bNNLS vector B.
weightWeights for each sample (array of length M).

Definition at line 259 of file nnls.c.

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}

Referenced by spectralDExp(), and spectralDMSurge().

◆ nnlsWghtSquared()

int nnlsWghtSquared ( int N,
int M,
double ** A,
double * b,
double * sweight )
extern

Algorithm for weighting the problem that is given to nnls-algorithm.

Square roots of weights are used because in nnls the difference w*A-w*b is squared. Here user must give squared weights; this makes calculation faster, when this function needs to be called many times.

Returns
Algorithm returns zero if successful, 1 if arguments are inappropriate.
See also
nnlsWghtSquared, qrLSQ, nnls
Parameters
NNNLS dimension N (nr of parameters).
MNNLS dimension M (nr of samples).
ANNLS matrix A.
bNNLS vector B.
sweightSquared weights for each sample (array of length M).

Definition at line 308 of file nnls.c.

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}

◆ qr()

int qr ( double ** A,
int m,
int n,
double * B,
double * X,
double * rnorm,
double * tau,
double * res,
double ** wws,
double * ws )
extern

Algorithm QR.

Solves a matrix form least square problem min||A x - b|| => A x =~ b (A is m*n matrix, m>=n) using the QR decomposition for overdetermined systems. Based on GNU Scientific Library, edited by Kaisa Liukko.

Instead of pointers for working space, NULL can be given to let this function to allocate and free the required memory.

See also
qrLSQ, nnls, qr_decomp
Returns
Function returns 0 if successful and 1 in case of invalid problem dimensions or memory allocation error.
Parameters
AOn entry, a[m][n] contains the m by n matrix A. On exit, a[][] contains the QR factorization.
mDimensions of matrix A are a[m][n].
nDimensions of matrix A are a[m][n].
BB[] is an m-size vector containing the right-hand side vector b.
XOn exit, x[] will contain the solution vector x (size of n).
rnormOn exit, rnorm (pointer to double) contains the squared Euclidean norm of the residual vector (R^2); enter NULL if not needed.
tauOn exit, tau[] will contain the householder coefficients (size of n); enter NULL, if not needed.
resAn m-size array of working space, res[]. On output contains residual b - Ax. Enter NULL to let qr() to handle it.
wwsm*n array of working space. Enter NULL to let qr() to handle it.
ws2m-array of working space. Enter NULL to let qr() to handle it.

Definition at line 411 of file qrlsq.c.

436 {
437 int i;
438 double *qrRes, *qrTau, **qrWws, *qrWs, *chain;
439
440 /* Check the parameters and data */
441 if(m<=0 || n<=0 || A==NULL || B==NULL || X==NULL) return(1);
442 if(m<n) return(1);
443
444 /* Allocate memory for working space, if required */
445 if(tau!=NULL) qrTau=tau; else qrTau=(double*)calloc(n, sizeof(double));
446 if(res!=NULL) qrRes=res; else qrRes=(double*)calloc(m, sizeof(double));
447 if(wws!=NULL) {
448 qrWws=wws; chain=(double*)NULL;
449 } else {
450 qrWws=(double**)malloc(m * sizeof(double*));
451 chain=(double*)malloc(m*n * sizeof(double));
452 for(i=0; i<m; i++) qrWws[i]=chain + i*n;
453 }
454 if(ws!=NULL) qrWs=ws; else qrWs=(double*)calloc(2*m, sizeof(double));
455 if(qrTau==NULL || qrRes==NULL || qrWws==NULL || qrWs==NULL) return(1);
456
457 /* Form the householder decomposition and solve the least square problem */
458 if(qr_decomp(A, m, n, qrTau, qrWws, qrWs)) return(2);
459 if(qr_solve(A, m, n, qrTau, B, X, qrRes, rnorm, qrWws, qrWs)) return(3);
460
461 /* Free working space, if it was allocated here */
462 //if(tau==NULL || res==NULL || wws==NULL || ws==NULL) printf("free in qr()\n");
463 if(tau==NULL) free(qrTau);
464 if(res==NULL) free(qrRes);
465 if(wws==NULL) {free(qrWws); free(chain);}
466 if(ws==NULL) free(qrWs);
467 for(i=0; i<n; i++) if(isnan(X[i])) return(4);
468 return(0);
469} /* qr */
int qr_solve(double **QR, int M, int N, double *tau, double *b, double *x, double *residual, double *resNorm, double **cchain, double *chain)
Definition qrlsq.c:563
int qr_decomp(double **a, int M, int N, double *tau, double **cchain, double *chain)
Definition qrlsq.c:493

◆ qr_decomp()

int qr_decomp ( double ** a,
int M,
int N,
double * tau,
double ** cchain,
double * chain )
extern

Factorise a general M x N matrix A into A = Q R , where Q is orthogonal (M x M) and R is upper triangular (M x N).

Q is stored as a packed set of Householder vectors in the strict lower triangular part of the input matrix A and a set of coefficients in vector tau.

R is stored in the diagonal and upper triangle of the input matrix.

The full matrix for Q can be obtained as the product Q = Q_1 Q_2 .. Q_k and it's transform as the product Q^T = Q_k .. Q_2 Q_1 , where k = min(M,N) and Q_i = (I - tau_i * h_i * h_i^T) and where h_i is a Householder vector h_i = [1, A(i+1,i), A(i+2,i), ... , A(M,i)]. This storage scheme is the same as in LAPACK.

NOTICE! The calling program must take care that pointer tau is of size N or M, whichever is smaller.

See also
qr
Returns
Function returns 0 if ok.
Parameters
acontains coefficient matrix A (m*n) as input and factorisation QR as output.
Mnr of rows in matrix A.
Nnr of columns in matrix A.
tauVector for householder coefficients, of length N or M, whichever is smaller.
cchainm*n array of working space.
chainm size array of working space.

Definition at line 493 of file qrlsq.c.

506 {
507 //printf("qr_decomp()\n");
508 int i, m, n, MNmin;
509 double *subvector, **submatrix;
510
511 /* Local variables */
512 if(M<N) MNmin=M; else MNmin=N;
513 if(MNmin<1 || a==NULL || tau==NULL || cchain==NULL || chain==NULL) return(1);
514 subvector=chain;
515 submatrix=cchain;
516
517 for(i=0; i<MNmin; i++) {
518 //printf("i=%d (MNmin=%d)\n", i, MNmin);
519 /* Compute the Householder transformation to reduce the j-th column of the matrix A to
520 a multiple of the j-th unit vector. Householder vector h_i is saved in the lower triangular
521 part of the column and Householder coefficient tau_i in the vector tau. */
522 for(m=i; m<M; m++) {
523 //printf("subvector[%d]=a[%d][%d]\n", m-1, m, i);
524 subvector[m-i]=a[m][i];
525 }
526 tau[i] = householder_transform(subvector, M-i);
527 for(m=i; m<M; m++) a[m][i]=subvector[m-i];
528
529 /* Apply the transformation to the remaining columns to get upper triangular part of matrix R */
530 if(i+1 < N) {
531 printf(" apply transformation\n");
532 for(m=i; m<M; m++) for(n=i+1; n<N; n++) {
533 if((m-i)<0 || (m-i)>=M || (n-i-1)<0 || (n-i-1)>=N) printf("OVERFLOW!\n");
534 submatrix[m-i][n-i-1]=a[m][n];
535 }
536 if(householder_hm(tau[i], subvector, submatrix, M-i, N-i)) return(2);
537 for(m=i; m<M; m++) for(n=i+1; n<N; n++)
538 a[m][n]=submatrix[m-i][n-i-1];
539 }
540 }
541
542 return(0);
543}
int householder_hm(double tau, double *vector, double **matrix, int rowNr, int columnNr)
Definition hholder.c:87
double householder_transform(double *v, int N)
Definition hholder.c:33

Referenced by qr().

◆ qr_solve()

int qr_solve ( double ** QR,
int M,
int N,
double * tau,
double * b,
double * x,
double * residual,
double * resNorm,
double ** cchain,
double * chain )
extern

Find the least squares solution to the overdetermined system

A x = b

for m >= n using the QR factorisation A = Q R. qr_decomp() must be used prior to this function in order to form the QR factorisation of A. Solution is formed in the following order: QR x = b => R x = Q^T b => x = R^-1 (Q^T b)

NOTICE! The calling program must take care that pointers b, x and residual are of the right size.

See also
qr, qr_decomp
Returns
Function returns 0 if ok.
Parameters
QRm*n matrix containing householder vectors of A.
Mnr of rows in matrix A.
Nnr of columns in matrix A.
tauvector containing householder coefficients tau; length is M or N, whichever is smaller.
bContains m-size vector b of A x = b.
xsolution vector x of length n.
residualresidual vector of length m.
resNormnorm^2 of the residual vector; enter NULL if not needed.
cchainm*n array of the working space.
chain2m length array of the working space.

Definition at line 563 of file qrlsq.c.

584 {
585 //printf("qr_solve()\n");
586 if(QR==NULL || tau==NULL || b==NULL || x==NULL || residual==NULL) return(1);
587 if(cchain==NULL || chain==NULL) return(1);
588 if(M<1 || N<1) return(2);
589
590 int m, n;
591 double **Rmatrix;
592
593 /* Local variable */
594 Rmatrix=cchain;
595
596 /* Get matrix R from the upper triangular part of QR
597 First the rows N - M-1 are eliminated from R matrix*/
598 for(m=0; m<N; m++) for(n=0; n<N; n++) Rmatrix[m][n]=QR[m][n];
599 for(m=0; m<M; m++) residual[m]=b[m];
600
601 /* Compute b = Q^T b */
602 if(qr_QTvec(M, N, QR, tau, residual, chain)) return(3);
603
604 /* Solve R x = b by computing x = R^-1 b */
605 for(n=0; n<N; n++) x[n]=residual[n];
606 if(qr_invRvec(N, Rmatrix, x)) return(4);
607
608 /* Compute residual = b - A x = Q (Q^T b - R x) */
609 for(n=0; n<N; n++) residual[n]=0.0;
610 /* Compute residual= Q*residual */
611 if(qr_Qvec(M, N, QR, tau, residual, chain)) return(4);
612
613 /* Compute norm^2 of the residual vector, if needed */
614 if(resNorm!=NULL)
615 for(m=0, *resNorm=0.0; m<M; m++) *resNorm +=residual[m]*residual[m];
616
617 return(0);
618}

Referenced by qr().

◆ qrLH()

int qrLH ( const unsigned int m,
const unsigned int n,
double * a,
double * b,
double * x,
double * r2 )
extern

Solve over-determined least-squares problem A x ~ b using successive Householder rotations.

This routine is based on the text and Fortran code in C.L. Lawson and R.J. Hanson, Solving Least Squares Problems, Prentice-Hall, Englewood Cliffs, New Jersey, 1974, and Fortran code by R.L. Parker and P.B. Stark.

Returns
Returns 0 when successful, 1 if system is singular, and 2 in case of other errors, including that system is under-determined.
Parameters
mNumber of samples in matrix A and the length of vector b.
nNumber of parameters in matrix A and the length of vector x. The n must be smaller or equal to m.
aPointer to matrix A; matrix must be given as an n*m array, containing n consecutive m-length vectors. Contents of A are modified in this routine.
bPointer to vector b of length n. Contents of b are modified in this routine.
xPointer to the result vector x of length n.
r2Pointer to a double value, in where the sum of squared residuals is written.

Definition at line 946 of file qrlsq.c.

963 {
964 /* Check the input */
965 if(a==NULL || b==NULL || x==NULL || r2==NULL) return(2);
966 if(n<1 || m<n) {*r2=nan(""); return(2);}
967
968 /* Initiate output to zeroes, in case of exit because of singularity */
969 for(unsigned int ni=0; ni<n; ni++) x[ni]=0.0;
970 *r2=0.0;
971
972 /* Rotates matrix A into upper triangular form */
973 for(unsigned int ni=0; ni<n; ni++) {
974 /* Find constants for rotation and diagonal entry */
975 double sq=0.0;
976 for(unsigned int mi=ni; mi<m; mi++) sq+=a[mi + ni*m]*a[mi + ni*m];
977 if(sq==0.0) return(1);
978 double qv1=-copysign(sqrt(sq), a[ni + ni*m]);
979 double u1=a[ni + ni*m] - qv1;
980 a[ni + ni*m]=qv1;
981 unsigned int ni1=ni+1;
982 /* Rotate the remaining columns of sub-matrix. */
983 for(unsigned int nj=ni1; nj<n; nj++) {
984 double dot=u1*a[ni + nj*m];
985 for(unsigned int mi=ni1; mi<m; mi++)
986 dot+=a[mi + nj*m] * a[mi + ni*m];
987 double c=dot/fabs(qv1*u1);
988 for(unsigned int mi=ni1; mi<m; mi++)
989 a[mi + nj*m]-=c*a[mi + ni*m];
990 a[ni + nj*m]-=c*u1;
991 }
992 /* Rotate vector B */
993 double dot=u1*b[ni];
994 for(unsigned int mi=ni1; mi<m; mi++)
995 dot+=b[mi]*a[mi + ni*m];
996 double c=dot/fabs(qv1*u1);
997 b[ni]-=c*u1;
998 for(unsigned int mi=ni1; mi<m; mi++)
999 b[mi]-=c*a[mi + ni*m];
1000 } // end of rotation loop
1001
1002 /* Solve triangular system by back-substitution. */
1003 for(unsigned int ni=0; ni<n; ni++) {
1004 int k=n-ni-1;
1005 double s=b[k];
1006 for(unsigned int nj=k+1; nj<n; nj++)
1007 s-=a[k + nj*m] * x[nj];
1008 if(a[k + k*m]==0.0) return(1);
1009 x[k]=s/a[k + k*m];
1010 }
1011
1012 /* Calculate the sum of squared residuals. */
1013 *r2=0.0;
1014 for(unsigned int mi=n; mi<m; mi++)
1015 *r2 += b[mi]*b[mi];
1016
1017 return(0);
1018}

Referenced by bvls().

◆ qrLSQ()

int qrLSQ ( double ** mat,
double * rhs,
double * sol,
const unsigned int rows,
const unsigned int cols,
double * r2 )
extern

QR least-squares solving routine.

Solves a matrix form least square problem min||A x - b|| => A x =~ b (A is m*n matrix, m>=n) using the QR decomposition for overdetermined systems

Author
: Michael Mazack License: Public Domain. Redistribution and modification without restriction is granted. If you find this code helpful, please let the author know (https://mazack.org). Small editions by Vesa Oikonen when added to tpcclib.
See also
nnls, qr
Todo
Check that modification in one subroutine is ok, and add possibility to provide working space for the main and sub-functions.
Returns
Returns 0 if ok.
Parameters
matPointer to the row-major matrix (2D array), A[rows][cols]; not modified.
rhsVector b[rows]; modified to contain the computed (fitted) b[], that is, matrix-vector product A*x.
solSolution vector x[cols]; solution x corresponds to the solution of both the modified and original systems A and B.
rowsNumber of rows (samples) in matrix A and length of vector B.
colsNumber of cols (parameters) in matrix A and length of vector X.
r2Pointer to value where R^2, the difference between original and computed right hand side (b); enter NULL if not needed.

Definition at line 72 of file qrlsq.c.

88 {
89 if(rows<1 || cols<1) return(1);
90 if(mat==NULL || rhs==NULL || sol==NULL) return(2);
91
92 unsigned int i, j, max_loc;
93 unsigned int *p=NULL;
94 double *buf=NULL, *ptr, *v=NULL, *orig_b=NULL, **A=NULL;
95
96 /* Allocate memory for index vector and Householder transform vector */
97 /* and original data matrix and vector. */
98 p=malloc(sizeof(unsigned int)*cols);
99 A=malloc(sizeof(double*)*rows);
100 buf=malloc(sizeof(double)*(rows*cols+rows+rows));
101 if(p==NULL || A==NULL || buf==NULL) {
102 free(p); free(A); free(buf);
103 return(3);
104 }
105 ptr=buf;
106 for(i=0; i<rows; i++) {A[i]=ptr; ptr+=cols;}
107 v=ptr; ptr+=rows; orig_b=ptr;
108 /* copy the original data */
109 for(i=0; i<rows; i++) {
110 orig_b[i]=rhs[i];
111 for(j=0; j<cols; j++) A[i][j]=mat[i][j];
112 }
113
114 /* Initial permutation vector. */
115 for(i=0; i<cols; i++) p[i]=i;
116
117 /* Apply rotators to make R and Q'*b */
118 for(i=0; i<cols; i++) {
119 if(qr_get_next_col(A, rows, cols, i, p, &max_loc)==0)
120 qr_swap_cols(p, i, max_loc);
121 qr_householder(A, rows, cols, i, p[i], v);
122 qr_apply_householder(A, rhs, rows, cols, v, i, p);
123 }
124
125 /* Back solve Rx = Q'*b */
126 qr_back_solve(A, rhs, rows, cols, sol, p);
127
128 /* Compute fitted b[] (matrix-vector product A*x) using non-modified A */
129 for(i=0; i<rows; i++) {
130 rhs[i]=0.0;
131 for(j=0; j<cols; j++) rhs[i]+=mat[i][j]*sol[j];
132 }
133
134 /* Compute R^2, if requested */
135 if(r2!=NULL) {
136 double ss=0, d;
137 for(i=0; i<rows; i++) {
138 d=orig_b[i]-rhs[i];
139 ss+=d*d;
140 }
141 *r2=ss;
142 }
143
144 /* Collect garbage. */
145 free(p); free(A); free(buf);
146 return(0);
147}

◆ qrSimpleLSQ()

int qrSimpleLSQ ( double ** A,
double * B,
int M,
int N,
double * X,
double * r2 )
extern

Simplistic QR least-squares solving routine.

Reference: Máté A. Introduction to Numerical Analysis with C programs. Chapter 38. Overdetermined systems of linear equations. Brooklyn College of the City University of New York, 2014.

See also
qrLSQ
Returns
Function returns 0 when successful.
Parameters
AMatrix A[M][N].
BVector B[M].
Mnr of rows in matrix A, must be >=N.
Nnr of columns in matrix A, must be <=M.
XVector X of length N for the results.
r2Pointer to value where R^2, the difference between original and computed right hand side (b); enter NULL if not needed.

Definition at line 854 of file qrlsq.c.

868 {
869 //printf("qrSimpleLSQ()\n");
870 if(A==NULL || B==NULL || X==NULL || N<1 || M<N) return(1);
871
872 const double closeZero=1.0E-20;
873
874 double cc[M], orig_B[M];
875 double p[M][N], c[M][N];
876
877 /* Householder transformation of matrix A into matrix P */
878 for(int n=0; n<N; n++) {
879 for(int nn=0; nn<n; nn++) p[nn][n]=0.0;
880 p[n][n]=0.0;
881 for(int m=n; m<M; m++) p[n][n]+=A[m][n]*A[m][n];
882 p[n][n]=copysign(sqrt(p[n][n]), A[n][n]);
883 p[n][n]+=A[n][n];
884 if(fabs(p[n][n])<closeZero) return(2);
885 for(int m=n+1; m<M; m++) p[m][n]=A[m][n];
886 double norm=0.0;
887 for(int m=n; m<M; m++) norm+=p[m][n]*p[m][n];
888 norm=sqrt(norm);
889 for(int m=n; m<M; m++) p[m][n]/=norm;
890 for(int m=n; m<M; m++) {
891 for(int nn=n; nn<N; nn++) {
892 c[m][nn]=A[m][nn];
893 for(int mm=n; mm<M; mm++) c[m][nn]-=2.0*p[m][n]*p[mm][n]*A[mm][nn];
894 }
895 }
896 for(int m=n; m<M; m++)
897 for(int nn=n; nn<N; nn++) A[m][nn]=c[m][nn];
898 }
899
900 /* Keep the original B[] for R^2 calculation */
901 for(int m=0; m<M; m++) orig_B[m]=B[m];
902
903 /* Compute P'b */
904 for(int n=0; n<N; n++) {
905 for(int m=n; m<M; m++) {
906 cc[m]=B[m];
907 for(int mm=n; mm<M; mm++) cc[m]-=2.0*p[m][n]*p[mm][n]*B[mm];
908 }
909 for(int m=n; m<M; m++) B[m]=cc[m];
910 }
911
912 /* Solve the linear system with backward substitution */
913 X[N-1]=B[N-1]/A[N-1][N-1];
914 for(int n=N-2; n>=0; n--) {
915 X[n]=B[n];
916 for(int nn=n+1; nn<N; nn++) X[n]-=A[n][nn]*X[nn];
917 X[n]/=A[n][n];
918 }
919
920 /* Compute R^2, if requested */
921 if(r2!=NULL) {
922 double ss=0, d;
923 for(int m=0; m<M; m++) {
924 d=orig_B[m]-B[m];
925 ss+=d*d;
926 }
927 *r2=ss;
928 }
929
930 return(0);
931}

◆ qrWeight()

int qrWeight ( int N,
int M,
double ** A,
double * b,
double * weight,
double * ws )
extern

Algorithm for weighting the problem that is given to QR algorithm. Square roots of weights are used because in QR the difference w*A-w*b is squared.

See also
qrWeightRm, qrLSQ, qr
Todo
Add tests.
Returns
Algorithm returns zero if successful, otherwise <>0.
Parameters
NDimensions of matrix A are a[m][n].
MDimensions of matrix A are a[m][n]; size of vector B is m.
AMatrix a[m][n] for QR, contents will be weighted here.
bB[] is an m-size vector for QR, contents will be weighted here.
weightPointer to array of size m, which contains sample weights, used here to weight matrix A and vector b.
wsm-sized vector for working space; enter NULL to allocate locally.

Definition at line 745 of file qrlsq.c.

759 {
760 int n, m;
761 double *w;
762
763 /* Check the arguments */
764 if(N<1 || M<1 || A==NULL || b==NULL || weight==NULL) return(1);
765
766 /* Allocate memory, if necessary */
767 if(ws==NULL) {
768 w=(double*)malloc(M*sizeof(double)); if(w==NULL) return(2);
769 } else {
770 w=ws;
771 }
772
773 /* Check that weights are not zero and get the square roots of them to w[]. */
774 for(m=0; m<M; m++) {
775 if(weight[m]<=1.0e-100) w[m]=1.0e-50;
776 else w[m]=sqrt(weight[m]);
777 }
778
779 /* Multiply rows of matrix A and elements of vector b with weights. */
780 for(m=0; m<M; m++) {
781 for(n=0; n<N; n++) A[m][n]*=w[m];
782 b[m]*=w[m];
783 }
784
785 if(ws==NULL) free(w);
786 return(0);
787}

◆ qrWeightRm()

int qrWeightRm ( int N,
int M,
double ** A,
double * b,
double * weight,
double * ws )
extern

Remove the weights from data provided to QR LSQ algorithms.

See also
qrWeight, qrLSQ, qr
Todo
Add tests.
Returns
Algorithm returns zero if successful, otherwise <>0.
Parameters
NDimensions of matrix A are a[m][n].
MDimensions of matrix A are a[m][n]; size of vector B is m.
AMatrix a[m][n] for QR, weights will be removed here; enter NULL if not needed.
bB[] is an m-size vector for QR, weights will be removed here; enter NULL if not needed here.
weightPointer to array of size m, which contains sample weights, used here to weight matrix A and vector b.
wsm-sized vector for working space; enter NULL to allocate locally

Definition at line 796 of file qrlsq.c.

811 {
812 int n, m;
813 double *w;
814
815 /* Check the arguments */
816 if(N<1 || M<1 || weight==NULL) return(1);
817 if(A==NULL && b==NULL) return(0); // nothing to do
818
819 /* Allocate memory, if necessary */
820 if(ws==NULL) {
821 w=(double*)malloc(M*sizeof(double)); if(w==NULL) return(2);
822 } else {
823 w=ws;
824 }
825
826 /* Check that weights are not zero and get the square roots of them to w[] */
827 for(m=0; m<M; m++) {
828 if(weight[m]<=1.0e-100) w[m]=1.0e-50;
829 else w[m]=sqrt(weight[m]);
830 }
831
832 /* Multiply rows of matrix A and elements of vector b with weights */
833 for(m=0; m<M; m++) {
834 if(A!=NULL) for(n=0; n<N; n++) A[m][n]/=w[m];
835 if(b!=NULL) b[m]/=w[m];
836 }
837
838 if(ws==NULL) free(w);
839 return(0);
840}

◆ rootsCubic()

int rootsCubic ( const double a,
const double b,
const double c,
double * x1,
double * x2,
double * x3 )
extern

Find the real roots of cubic equation x^3 + a x^2 + b x + c = 0.

The number of real roots can be 1 or 3, but coincident roots are possible. Root values, excluding duplicates and triplicates, will be placed in pointers x1, x2, and x3 in ascending order, or set to NaN.

Based on GNU Scientific Library function gsl_poly_solve_cubic.

See also
rootsQuadratic, fitLine
Returns
Returns the number of real individual roots, and zero in case of an error.
Parameters
aInput: Parameter a of the cubic equation.
bInput: Parameter b of the cubic equation.
cInput: Parameter c of the cubic equation.
x1Output: Pointer for root 1 value. Will be set to NaN if there are no real roots.
x2Output: Pointer for root 2 value. Will be set to NaN if there is only one individual real root.
x3Output: Pointer for root 3 value. Will be set to NaN if there are only two individual real roots.

Definition at line 30 of file roots.c.

43 {
44 if(x1==NULL || x2==NULL || x3==NULL) return(0);
45 *x1=*x2=*x3=nan("");
46
47 if(a==0 && b==0 && c==0) return(0);
48 if(!isfinite(a) || !isfinite(b) || !isfinite(c)) return(0);
49
50 long double q=(a*a - 3*b);
51 long double r=(2*a*a*a - 9*a*b + 27*c);
52
53 long double Q=q/9;
54 long double R=r/54;
55
56 long double Q3=Q*Q*Q;
57 long double R2=R*R;
58
59 long double CR2=729*r*r;
60 long double CQ3=2916*q*q*q;
61
62 if(R==0 && Q==0) {
63 *x1=-a/3; // *x2=-a/3; *x3=-a/3;
64 return(1);
65 } else if(CR2==CQ3) {
66 long double sqrtQ=sqrt(Q);
67 if(R>0) {
68 *x1=-2*sqrtQ - a/3;
69 *x2=sqrtQ - a/3; // *x3=sqrtQ - a/3;
70 } else {
71 *x1=-sqrtQ - a/3; // *x2=-sqrtQ - a/3; *x3=2*sqrtQ - a/3;
72 *x2=2*sqrtQ - a/3;
73 }
74 return(2);
75 } else if(R2<Q3) {
76 double ratio=copysign(sqrt(R2/Q3), R);
77 //if(!isfinite(ratio)) return(0);
78 double theta=acos(ratio);
79 double norm=-2*sqrt(Q);
80 //if(!isfinite(norm)) return(0);
81 *x1=norm*cos(theta/3) - a/3;
82 *x2=norm*cos((theta + 2.0*M_PI)/3) - a/3;
83 *x3=norm*cos((theta - 2.0*M_PI)/3) - a/3;
84 if(*x1>*x2) {double s=*x1; *x1=*x2; *x2=s;}
85 if(*x2>*x3) {
86 double s=*x2; *x2=*x3; *x3=s;
87 if(*x1>*x2) {double s=*x1; *x1=*x2; *x2=s;}
88 }
89 return(3);
90 } else {
91 long double A = -copysign(pow(fabsl(R) + sqrt(R2-Q3), 1.0/3.0), R);
92 long double B=Q/A;
93 *x1=A + B - a/3;
94 return(1);
95 }
96}

◆ rootsQuadratic()

int rootsQuadratic ( const double a,
const double b,
const double c,
double * x1,
double * x2 )
extern

Find the real roots of quadratic equation a x^2 + b x + c = 0.

The number of real roots can be 0, 1, or 2, but coincident roots are possible. Root values, excluding duplicate value, will be placed in pointers x1 and x2 in ascending order, or set to NaN.

Based on GNU Scientific Library function gsl_poly_solve_quadratic.

See also
rootsCubic, fitLine
Returns
Returns the number of real roots, excluding duplicate solutions.
Parameters
aInput: Parameter a of the quadratic equation.
bInput: Parameter b of the quadratic equation.
cInput: Parameter c of the quadratic equation.
x1Output: Pointer for root 1 value. Will be set to NaN if there are no real roots.
x2Output: Pointer for root 2 value. Will be set to NaN if there is only one individual real root.

Definition at line 111 of file roots.c.

122 {
123 if(x1==NULL || x2==NULL) return(0);
124 *x1=*x2=nan("");
125
126 if(!isfinite(a) || !isfinite(b) || !isfinite(c)) return(0);
127
128 if(a==0) {
129 if(b==0) return(0);
130 else {*x1=-c/b; /* *x2=-c/b;*/ return(1);}
131 }
132 long double d=b*b - 4*a*c;
133 if(d>0) {
134 if(b==0) {
135 long double r=fabs(sqrt(-c/a));
136 *x1=-r; *x2=r;
137 } else {
138 long double t=-0.5*(b + copysign(sqrt(d), b));
139 long double r1=t/a;
140 long double r2=c/t;
141 if(r1<r2) {*x1=r1; *x2=r2;} else {*x1=r2; *x2=r1;}
142 }
143 return(2);
144 } else if(d==0) {
145 *x1=-0.5*b/a; // *x2=-0.5*b/a;
146 return(1);
147 } else {
148 return(0);
149 }
150}