TPCCLIB
Loading...
Searching...
No Matches
qr.c
Go to the documentation of this file.
1
8/*****************************************************************************/
9#include "libtpcmodel.h"
10/*****************************************************************************/
11
12/*****************************************************************************/
14/* Local functions */
15int qr_get_next_col(
16 double **mat, const unsigned int rows, const unsigned int cols,
17 unsigned int row_pos, unsigned int *p, unsigned int *max_loc
18);
19void qr_swap_cols(
20 unsigned int *p, const unsigned int i, const unsigned int j
21);
22void qr_householder(
23 double **mat, const unsigned int rows, const unsigned int cols,
24 const unsigned int row_pos, const unsigned int col_pos, double *result
25);
26void qr_apply_householder(
27 double **mat, double *rhs, const unsigned int rows, const unsigned int cols,
28 double *house, const unsigned int row_pos, unsigned int *p
29);
30void qr_back_solve(
31 double **mat, double *rhs, const unsigned int rows, const unsigned int cols,
32 double *sol, unsigned int *p
33);
35/*****************************************************************************/
36
37/*****************************************************************************/
56 double **mat,
59 double *rhs,
62 double *sol,
64 const unsigned int rows,
66 const unsigned int cols,
69 double *r2
70) {
71 if(rows<1 || cols<1) return(1);
72 if(mat==NULL || rhs==NULL || sol==NULL) return(2);
73
74 unsigned int i, j, max_loc;
75 unsigned int *p=NULL;
76 double *buf=NULL, *ptr, *v=NULL, *orig_b=NULL, **A=NULL;
77
78 /* Allocate memory for index vector and Householder transform vector */
79 /* and original data matrix and vector. */
80 p=malloc(sizeof(unsigned int)*cols);
81 A=malloc(sizeof(double*)*rows);
82 buf=malloc(sizeof(double)*(rows*cols+rows+rows));
83 if(p==NULL || A==NULL || buf==NULL) {
84 free(p); free(A); free(buf);
85 return(3);
86 }
87 ptr=buf;
88 for(i=0; i<rows; i++) {A[i]=ptr; ptr+=cols;}
89 v=ptr; ptr+=rows; orig_b=ptr;
90 /* copy the original data */
91 for(i=0; i<rows; i++) {
92 orig_b[i]=rhs[i];
93 for(j=0; j<cols; j++) A[i][j]=mat[i][j];
94 }
95
96 /* Initial permutation vector. */
97 for(i=0; i<cols; i++) p[i]=i;
98
99 /* Apply rotators to make R and Q'*b */
100 for(i=0; i<cols; i++) {
101 if(qr_get_next_col(A, rows, cols, i, p, &max_loc)==0)
102 qr_swap_cols(p, i, max_loc);
103 qr_householder(A, rows, cols, i, p[i], v);
104 qr_apply_householder(A, rhs, rows, cols, v, i, p);
105 }
106
107 /* Back solve Rx = Q'*b */
108 qr_back_solve(A, rhs, rows, cols, sol, p);
109
110 /* Compute fitted b[] (matrix-vector product A*x) using non-modified A */
111 for(i=0; i<rows; i++) {
112 rhs[i]=0.0;
113 for(j=0; j<cols; j++) rhs[i]+=mat[i][j]*sol[j];
114 }
115
116 /* Compute R^2, if requested */
117 if(r2!=NULL) {
118 double ss=0, d;
119 for(i=0; i<rows; i++) {
120 d=orig_b[i]-rhs[i];
121 ss+=d*d;
122 }
123 *r2=ss;
124 }
125
126 /* Collect garbage. */
127 free(p); free(A); free(buf);
128 return(0);
129}
130
132
135int qr_get_next_col(
137 double **mat,
139 const unsigned int rows,
141 const unsigned int cols,
143 const unsigned int row_pos,
145 unsigned int *p,
147 unsigned int *max_loc
148) {
149 if(mat==NULL || rows<1 || cols<1 || p==NULL) return(-1);
150
151 unsigned int i, j, maxloc;
152 double col_norm, max_norm;
153
154 // Compute the norms of the sub columns and find the maximum
155 max_norm=DBL_MIN; maxloc=0;
156 for(j=0; j<cols; j++) {
157 col_norm=0;
158 for(i=row_pos; i<rows; i++) col_norm+=mat[i][p[j]]*mat[i][p[j]];
159 if(col_norm>max_norm) {max_norm=col_norm; maxloc=j;}
160 }
161 if(max_norm!=DBL_MIN) {
162 if(max_loc!=NULL) *max_loc=maxloc;
163 return(0);
164 }
165 return(1);
166}
167
169void qr_swap_cols(unsigned int *p, const unsigned int i, const unsigned int j)
170{
171 unsigned int temp;
172 temp=p[i]; p[i]=p[j]; p[j]=temp;
173}
174
176void qr_householder(
178 double **mat,
180 const unsigned int rows,
182 const unsigned int cols,
184 const unsigned int row_pos,
186 const unsigned int col_pos,
188 double *result
189) {
190 if(rows<1 || cols<1 || mat==NULL || result==NULL) return;
191
192 unsigned int i;
193 double norm=0.0;
194
195 for(i=row_pos; i<rows; i++) norm+=mat[i][col_pos]*mat[i][col_pos];
196 if(norm==0.0) return;
197
198 norm=sqrt(norm);
199 result[0]=(mat[row_pos][col_pos]-norm);
200 for(i=1; i<(rows-row_pos); i++) result[i]=mat[i+row_pos][col_pos];
201
202 norm=0.0;
203 for(i=0; i<(rows-row_pos); i++) norm+=result[i]*result[i];
204 if(norm==0) return;
205
206 norm=sqrt(norm);
207 for(i=0; i<(rows-row_pos); i++) result[i]*=(1.0/norm);
208}
209
211void qr_apply_householder(
213 double **mat,
215 double *rhs,
217 const unsigned int rows,
219 const unsigned int cols,
221 double *house,
223 const unsigned int row_pos,
225 unsigned int *p
226) {
227 if(mat==NULL || rhs==NULL || rows<1 || cols<1 || house==NULL || p==NULL) return;
228
229 unsigned int i, j, k, n;
230 double sum;
231 double **hhmat;
232 double **mat_cpy;
233 double *rhs_cpy;
234
235 // Get the dimensions for the Q matrix.
236 n=rows-row_pos;
237
238 // Allocate memory.
239 hhmat=malloc(sizeof(double*)*n);
240 for(i=0; i<n; i++) hhmat[i]=malloc(sizeof(double)*n);
241 mat_cpy=malloc(sizeof(double*)*rows);
242 for(i=0; i<rows; i++) mat_cpy[i]=malloc(sizeof(double)*cols);
243 rhs_cpy=malloc(sizeof(double)*rows);
244
245 // Copy the matrix.
246 for(i=0; i<rows; i++)
247 for(j=0; j<cols; j++)
248 mat_cpy[i][j]=mat[i][j];
249
250 // Copy the right hand side.
251 for(i=0; i<rows; i++) rhs_cpy[i]=rhs[i];
252
253 // Build the Q matrix from the Householder transform.
254 for(j=0; j<n; j++)
255 for(i=0; i<n; i++)
256 if(i!=j) hhmat[i][j]=-2.0*house[j]*house[i];
257 else hhmat[i][j]=1.0-2.0*house[j]*house[i];
258
259 // Multiply by the Q matrix.
260 for(k=0; k<cols; k++)
261 for(j=0; j<n; j++) {
262 sum=0.0;
263 for(i=0; i<n; i++) sum+=hhmat[j][i]*mat_cpy[i+row_pos][p[k]];
264 mat[j+row_pos][p[k]]=sum;
265 }
266
267 // Multiply the rhs by the Q matrix.
268 for(j=0; j<n; j++) {
269 sum=0.0;
270 for(i=0; i<n; i++) sum+=hhmat[i][j]*rhs_cpy[i+row_pos];
271 rhs[j+row_pos]=sum;
272 }
273
274 // Collect garbage.
275 for(i=0; i<(rows-row_pos); i++) free(hhmat[i]);
276 for(i=0; i<rows; i++) free(mat_cpy[i]);
277 free(hhmat);
278 free(mat_cpy);
279 free(rhs_cpy);
280}
281
283void qr_back_solve(
285 double **mat,
287 double *rhs,
289 const unsigned int rows,
291 const unsigned int cols,
293 double *sol,
295 unsigned int *p
296) {
297 if(mat==NULL || rhs==NULL || rows<1 || cols<1 || sol==NULL || p==NULL)
298 return;
299
300 unsigned int i, j, bottom;
301 double sum;
302
303 /* Fill the solution with zeros initially. */
304 for(i=0; i<cols; i++) sol[i]=0.0;
305
306 /* Find the first non-zero row from the bottom and start solving from here. */
307 i=rows-1; bottom=i;
308 while(1) {
309 if(fabs(mat[i][p[cols-1]]) > 2.0*DBL_MIN) {bottom=i; break;}
310 if(i==0) break; else i--;
311 }
312
313 /* Standard back solving routine starting at the first non-zero diagonal. */
314 i=bottom;
315 while(1) {
316 sum=0.0;
317 j=cols-1;
318 while(1) {
319 if(j>i) sum+=sol[p[j]]*mat[i][p[j]];
320 if(j==0) break; else j--;
321 }
322 if(i<cols) { // Added by VO
323 if(mat[i][p[i]] > 2.0*DBL_MIN) sol[p[i]]=(rhs[i]-sum)/mat[i][p[i]];
324 else sol[p[i]]=0.0;
325 }
326 if(i==0) break; else i--;
327 }
328}
330/*****************************************************************************/
331
332/*****************************************************************************/
346int qr(
349 double **A,
351 int m,
353 int n,
355 double *B,
357 double *X,
360 double *rnorm,
363 double *tau,
366 double *res,
368 double **wws,
370 double *ws
371) {
372 int i;
373 double *qrRes, *qrTau, **qrWws, *qrWs, *chain;
374
375 /* Check the parameters and data */
376 if(m<=0 || n<=0 || A==NULL || B==NULL || X==NULL) return(1);
377 if(m<n) return(1);
378
379 /* Allocate memory for working space, if required */
380 if(tau!=NULL) qrTau=tau; else qrTau=(double*)calloc(n, sizeof(double));
381 if(res!=NULL) qrRes=res; else qrRes=(double*)calloc(m, sizeof(double));
382 if(wws!=NULL) {
383 qrWws=wws; chain=(double*)NULL;
384 } else {
385 qrWws=(double**)malloc(m * sizeof(double*));
386 chain=(double*)malloc(m*n * sizeof(double));
387 for(i=0; i<m; i++) qrWws[i]=chain + i*n;
388 }
389 if(ws!=NULL) qrWs=ws; else qrWs=(double*)calloc(2*m, sizeof(double));
390 if(qrTau==NULL || qrRes==NULL || qrWws==NULL || qrWs==NULL) return(1);
391
392 /* Form the householder decomposition and solve the least square problem */
393 if(qr_decomp(A, m, n, qrTau, qrWws, qrWs)) return(2);
394 if(qr_solve(A, m, n, qrTau, B, X, qrRes, rnorm, qrWws, qrWs)) return(3);
395
396 /* Free working space, if it was allocated here */
397 if(tau==NULL) free(qrTau);
398 if(res==NULL) free(qrRes);
399 if(wws==NULL) {free(qrWws); free(chain);}
400 if(ws==NULL) free(qrWs);
401 for(i=0; i<n; i++) if(isnan(X[i])) return(4);
402 return(0);
403} /* qr */
404/*****************************************************************************/
405
406/*****************************************************************************/
429 double **a,
431 int M,
433 int N,
435 double *tau,
437 double **cchain,
439 double *chain
440) {
441 //printf("qr_decomp()\n");
442 int i, m, n, MNmin;
443 double *subvector, **submatrix;
444
445 /* Local variables */
446 if(M<N) MNmin=M; else MNmin=N;
447 if(MNmin<1 || a==NULL || tau==NULL || cchain==NULL || chain==NULL) return(1);
448
449 subvector=chain;
450 submatrix=cchain;
451
452 for(i=0; i<MNmin; i++) {
453 //printf("i=%d (MNmin=%d)\n", i, MNmin);
454 /* Compute the Householder transformation to reduce the j-th column of the matrix A to
455 a multiple of the j-th unit vector. Householder vector h_i is saved in the lower triangular
456 part of the column and Householder coefficient tau_i in the vector tau. */
457 for(m=i; m<M; m++) subvector[m-i]=a[m][i];
458 tau[i] = householder_transform(subvector, M-i);
459 for(m=i; m<M; m++) a[m][i]=subvector[m-i];
460
461 /* Apply the transformation to the remaining columns to get upper triangular part of matrix R */
462 if(i+1 < N) {
463 for(m=i; m<M; m++)
464 for(n=i+1; n<N; n++)
465 submatrix[m-i][n-i-1]=a[m][n];
466 if(householder_hm(tau[i], subvector, submatrix, M-i, N-i)) return(2);
467 for(m=i; m<M; m++)
468 for(n=i+1; n<N; n++)
469 a[m][n]=submatrix[m-i][n-i-1];
470 }
471 }
472
473 return(0);
474}
475/*****************************************************************************/
476
477/*****************************************************************************/
494 double **QR,
496 int M,
498 int N,
500 double *tau,
502 double *b,
504 double *x,
506 double *residual,
508 double *resNorm,
510 double **cchain,
512 double *chain
513) {
514 //printf("qr_solve()\n");
515 if(QR==NULL || tau==NULL || b==NULL || x==NULL || residual==NULL) return(1);
516 if(cchain==NULL || chain==NULL) return(1);
517 if(M<1 || N<1) return(2);
518
519 int MNmin; if(M<N) MNmin=M; else MNmin=N;
520
521 int m, n;
522 double **Rmatrix=cchain;
523 double *h=chain;
524 double *w=chain+M;
525
526 /* Get matrix R from the upper triangular part of QR
527 First the rows N - M-1 are eliminated from R matrix*/
528 for(m=0; m<N; m++) for(n=0; n<N; n++) Rmatrix[m][n]=QR[m][n];
529 for(m=0; m<M; m++) residual[m]=b[m];
530
531 /* Compute b = Q^T b */
532 /* Form the product Q^T residual from householder vectors saved in the lower triangle of
533 QR matrix and householder coefficients saved in vector tau. */
534 for(int i=0; i<MNmin; i++) {
535 for(m=i; m<M; m++) h[m-i]=QR[m][i];
536 for(m=i; m<M; m++) w[m-i]=residual[m];
537 if(householder_hv(tau[i], M-i, h, w)) return(2);
538 for(m=i; m<M; m++) residual[m]=w[m-i];
539 }
540
541 /* Solve R x = b by computing x = R^-1 b */
542 for(n=0; n<N; n++) x[n]=residual[n];
543 /* back-substitution */
544 x[N-1]=x[N-1]/Rmatrix[N-1][N-1];
545 for(int i=N-2; i>=0; i--) {
546 for(int j=i+1; j<N; j++) x[i]-=Rmatrix[i][j]*x[j];
547 x[i]/=Rmatrix[i][i];
548 }
549
550 /* Compute residual = b - A x = Q (Q^T b - R x) */
551 for(n=0; n<N; n++) residual[n]=0.0;
552 /* Compute residual= Q*residual */
553 /* Form the product Q*residual from householder vectors saved in the lower triangle
554 of QR matrix and householder coefficients saved in vector tau. */
555 for(int i=MNmin-1; i>=0; i--) {
556 for(int m=i; m<M; m++) h[m-i]=QR[m][i];
557 for(int m=i; m<M; m++) w[m-i]=residual[m];
558 if(householder_hv(tau[i], M-i, h, w)) return(2);
559 for(int m=i; m<M; m++) residual[m]=w[m-i];
560 }
561
562 /* Compute norm^2 of the residual vector, if needed */
563 if(resNorm!=NULL)
564 for(m=0, *resNorm=0.0; m<M; m++) *resNorm +=residual[m]*residual[m];
565
566 return(0);
567}
568/*****************************************************************************/
569
570/*****************************************************************************/
578 int N,
580 int M,
582 double **A,
584 double *b,
587 double *weight,
589 double *ws
590) {
591 int n, m;
592 double *w;
593
594 /* Check the arguments */
595 if(N<1 || M<1 || A==NULL || b==NULL || weight==NULL) return(1);
596
597 /* Allocate memory, if necessary */
598 if(ws==NULL) {
599 w=(double*)malloc(M*sizeof(double)); if(w==NULL) return(2);
600 } else {
601 w=ws;
602 }
603
604 /* Check that weights are not zero and get the square roots of them to w[]. */
605 for(m=0; m<M; m++) {
606 if(weight[m]<=1.0e-100) w[m]=1.0e-50;
607 else w[m]=sqrt(weight[m]);
608 }
609
610 /* Multiply rows of matrix A and elements of vector b with weights. */
611 for(m=0; m<M; m++) {
612 for(n=0; n<N; n++) A[m][n]*=w[m];
613 b[m]*=w[m];
614 }
615
616 if(ws==NULL) free(w);
617 return(0);
618}
619/*****************************************************************************/
620
621/*****************************************************************************/
635 const unsigned int m,
638 const unsigned int n,
642 double *a,
645 double *b,
647 double *x,
649 double *r2
650) {
651 /* Check the input */
652 if(a==NULL || b==NULL || x==NULL || r2==NULL) return(2);
653 if(n<1 || m<n) {*r2=nan(""); return(2);}
654
655 /* Initiate output to zeroes, in case of exit because of singularity */
656 for(unsigned int ni=0; ni<n; ni++) x[ni]=0.0;
657 *r2=0.0;
658
659 /* Rotates matrix A into upper triangular form */
660 for(unsigned int ni=0; ni<n; ni++) {
661 /* Find constants for rotation and diagonal entry */
662 double sq=0.0;
663 for(unsigned int mi=ni; mi<m; mi++) sq+=a[mi + ni*m]*a[mi + ni*m];
664 if(sq==0.0) return(1);
665 double qv1=-copysign(sqrt(sq), a[ni + ni*m]);
666 double u1=a[ni + ni*m] - qv1;
667 a[ni + ni*m]=qv1;
668 unsigned int ni1=ni+1;
669 /* Rotate the remaining columns of sub-matrix. */
670 for(unsigned int nj=ni1; nj<n; nj++) {
671 double dot=u1*a[ni + nj*m];
672 for(unsigned int mi=ni1; mi<m; mi++)
673 dot+=a[mi + nj*m] * a[mi + ni*m];
674 double c=dot/fabs(qv1*u1);
675 for(unsigned int mi=ni1; mi<m; mi++)
676 a[mi + nj*m]-=c*a[mi + ni*m];
677 a[ni + nj*m]-=c*u1;
678 }
679 /* Rotate vector B */
680 double dot=u1*b[ni];
681 for(unsigned int mi=ni1; mi<m; mi++)
682 dot+=b[mi]*a[mi + ni*m];
683 double c=dot/fabs(qv1*u1);
684 b[ni]-=c*u1;
685 for(unsigned int mi=ni1; mi<m; mi++)
686 b[mi]-=c*a[mi + ni*m];
687 } // end of rotation loop
688
689 /* Solve triangular system by back-substitution. */
690 for(unsigned int ni=0; ni<n; ni++) {
691 int k=n-ni-1;
692 double s=b[k];
693 for(unsigned int nj=k+1; nj<n; nj++)
694 s-=a[k + nj*m] * x[nj];
695 if(a[k + k*m]==0.0) return(1);
696 x[k]=s/a[k + k*m];
697 }
698
699 /* Calculate the sum of squared residuals. */
700 *r2=0.0;
701 for(unsigned int mi=n; mi<m; mi++)
702 *r2 += b[mi]*b[mi];
703
704 return(0);
705}
706/*****************************************************************************/
707
708/*****************************************************************************/
int householder_hv(double tau, int size, double *v, double *w)
Definition hholder.c:107
int householder_hm(double tau, double *vector, double **matrix, int rowNr, int columnNr)
Definition hholder.c:68
double householder_transform(double *v, int N)
Definition hholder.c:23
Header file for libtpcmodel.
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 qr.c:633
int qr_weight(int N, int M, double **A, double *b, double *weight, double *ws)
Definition qr.c:576
int qrLSQ(double **mat, double *rhs, double *sol, const unsigned int rows, const unsigned int cols, double *r2)
QR least-squares solving routine.
Definition qr.c:54
int qr_solve(double **QR, int M, int N, double *tau, double *b, double *x, double *residual, double *resNorm, double **cchain, double *chain)
Definition qr.c:492
int qr(double **A, int m, int n, double *B, double *X, double *rnorm, double *tau, double *res, double **wws, double *ws)
Definition qr.c:346
int qr_decomp(double **a, int M, int N, double *tau, double **cchain, double *chain)
Definition qr.c:427