CLHEP 2.4.6.4
C++ Class Library for High Energy Physics
Loading...
Searching...
No Matches
MatrixLinear.cc
Go to the documentation of this file.
1// -*- C++ -*-
2// ---------------------------------------------------------------------------
3//
4// This file is a part of the CLHEP - a Class Library for High Energy Physics.
5//
6// This is the definition of special linear algebra functions for the
7// HepMatrix class.
8//
9// Many of these algorithms are taken from Golub and Van Loan.
10//
11
12#include "CLHEP/Matrix/Matrix.h"
13#include "CLHEP/Matrix/Vector.h"
14#include "CLHEP/Matrix/SymMatrix.h"
15
16#include <iostream>
17#include <vector>
18
19namespace CLHEP {
20
21static int sign(double x) { return (x>0 ? 1: -1);}
22
23/* -----------------------------------------------------------------------
24
25 The following contains stuff to try to do basic things with matrixes.
26 The functions are:
27
28 back_solve - Solves R*x = b where R is upper triangular.
29 Also has a variation that solves a number of equations
30 of this form in one step, where b is a matrix with
31 each column a different vector. See also solve.
32 col_givens - Does a column Givens update.
33 col_house - Does a column Householder update.
34 condition - Find the conditon number of a symmetric matrix.
35 diag_step - Implicit symmetric QR step with Wilkinson Shift
36 diagonalize - Diagonalize a symmetric matrix.
37 givens - algorithm 5.1.5 in Golub and Van Loan
38 house - Returns a Householder vector to zero elements.
39 house_with_update - Finds and does Householder reflection on matrix.
40 qr_inverse - Finds the inverse of a matrix. Note, often what you
41 really want is solve or backsolve, they can be much
42 quicker than inverse in many calculations.
43 min_line_dist - Takes a set of lines and returns the point nearest to
44 all the lines in the least squares sense.
45 qr_decomp - Does a QR decomposition of a matrix.
46 row_givens - Does a row Givens update.
47 row_house - Does a row Householder update.
48 qr_solve - Works like backsolve, except matrix does not need
49 to be upper triangular. For nonsquare matrix, it
50 solves in the least square sense.
51 tridiagonal - Does a Householder tridiagonalization of a symmetric
52 matrix.
53 ----------------------------------------------------------------------- */
54
55/* -----------------------------------------------------------------------
56 back_solve Version: 1.00 Date Last Changed: 2/9/93
57
58 This solves the system R*x=b where R is upper triangular. Since b
59 is most likely not interesting after this step, x is returned in b.
60 This is algorithm 3.1.2 in Golub & Van Loan
61 ----------------------------------------------------------------------- */
62
63void back_solve(const HepMatrix &R, HepVector *b)
64{
65 (*b)(b->num_row()) /= R(b->num_row(),b->num_row());
66 int n = R.num_col();
67 int nb = b->num_row();
68 HepMatrix::mIter br = b->m.begin() + b->num_row() - 2;
69 HepMatrix::mcIter Rrr = R.m.begin() + (nb-2) * (n+1);
70 for (int r=b->num_row()-1;r>=1;--r) {
71 HepMatrix::mIter bc = br+1;
72 HepMatrix::mcIter Rrc = Rrr+1;
73 for (int c=r+1;c<=b->num_row();c++) {
74 (*br)-=(*(Rrc++))*(*(bc++));
75 }
76 (*br)/=(*Rrr);
77 if(r>1) {
78 br--;
79 Rrr -= n+1;
80 }
81 }
82}
83
84/* -----------------------------------------------------------------------
85 Variation that solves a set of equations R*x=b in one step, where b
86 is a Matrix with columns each a different vector. Solution is again
87 returned in b.
88 ----------------------------------------------------------------------- */
89
90void back_solve(const HepMatrix &R, HepMatrix *b)
91{
92 int n = R.num_col();
93 int nb = b->num_row();
94 int nc = b->num_col();
95 HepMatrix::mIter bbi = b->m.begin() + (nb - 2) * nc;
96 for (int i=1;i<=b->num_col();i++) {
97 (*b)(b->num_row(),i) /= R(b->num_row(),b->num_row());
98 HepMatrix::mcIter Rrr = R.m.begin() + (nb-2) * (n+1);
99 HepMatrix::mIter bri = bbi;
100 for (int r=b->num_row()-1;r>=1;--r) {
101 HepMatrix::mIter bci = bri + nc;
102 HepMatrix::mcIter Rrc = Rrr+1;
103 for (int c=r+1;c<=b->num_row();c++) {
104 (*bri)-= (*(Rrc++)) * (*bci);
105 if(c<b->num_row()) bci += nc;
106 }
107 (*bri)/= (*Rrr);
108 if(r>1) {
109 Rrr -= (n+1);
110 bri -= nc;
111 }
112 }
113 bbi++;
114 }
115}
116
117/* -----------------------------------------------------------------------
118 col_givens Version: 1.00 Date Last Changed: 1/28/93
119
120 This does the same thing as row_givens, except it works for columns.
121 It replaces A with A*G.
122 ----------------------------------------------------------------------- */
123
124void col_givens(HepMatrix *A, double c,double ds,
125 int k1, int k2, int row_min, int row_max) {
126 if (row_max<=0) row_max = A->num_row();
127 int n = A->num_col();
128 HepMatrix::mIter Ajk1 = A->m.begin() + (row_min - 1) * n + k1 - 1;
129 HepMatrix::mIter Ajk2 = A->m.begin() + (row_min - 1) * n + k2 - 1;
130 for (int j=row_min;j<=row_max;j++) {
131 double tau1=(*Ajk1); double tau2=(*Ajk2);
132 (*Ajk1)=c*tau1-ds*tau2;(*Ajk2)=ds*tau1+c*tau2;
133 if(j<row_max) {
134 Ajk1 += n;
135 Ajk2 += n;
136 }
137 }
138}
139
140/* -----------------------------------------------------------------------
141 col_house Version: 1.00 Date Last Changed: 1/28/93
142
143 This replaces A with A*P where P=I-2v*v.T/(v.T*v). If row and col are
144 not one, then it only acts on the subpart of A, from A(row,col) to
145 A(A.num_row(),A.num_row()). For use with house, can pass V as a matrix.
146 Then row_start and col_start describe where the vector lies. It is
147 assumed to run from V(row_start,col_start) to
148 V(row_start+A.num_row()-row,col_start).
149 Since typically row_house comes after house, and v.normsq is calculated
150 in house, it is passed as a arguement. Also supplied without vnormsq.
151 This does a column Householder update.
152 ----------------------------------------------------------------------- */
153
154void col_house(HepMatrix *a,const HepMatrix &v,double vnormsq,
155 int row, int col, int row_start,int col_start) {
156 double beta=-2/vnormsq;
157
158 // This is a fast way of calculating w=beta*A.sub(row,n,col,n)*v
159
160 HepVector w(a->num_col()-col+1,0);
161/* not tested */
162 HepMatrix::mIter wptr = w.m.begin();
163 int n = a->num_col();
164 int nv = v.num_col();
165 HepMatrix::mIter acrb = a->m.begin() + (col-1) * n + (row-1);
166 int c;
167 for (c=col;c<=a->num_col();c++) {
168 HepMatrix::mcIter vp = v.m.begin() + (row_start-1) * nv + (col_start-1);
169 HepMatrix::mcIter acr = acrb;
170 for (int r=row;r<=a->num_row();r++) {
171 (*wptr)+=(*(acr++))*(*vp);
172 vp += nv;
173 }
174 wptr++;
175 if(c<a->num_col()) acrb += n;
176 }
177 w*=beta;
178
179 // Fast way of calculating A.sub=A.sub+w*v.T()
180
181 HepMatrix::mIter arcb = a->m.begin() + (row-1) * n + col-1;
182 wptr = w.m.begin();
183 for (int r=row; r<=a->num_row();r++) {
184 HepMatrix::mIter arc = arcb;
185 HepMatrix::mcIter vp = v.m.begin() + (row_start-1) * nv + col_start;
186 for (c=col;c<=a->num_col();c++) {
187 (*(arc++))+=(*vp)*(*wptr);
188 vp += nv;
189 }
190 wptr++;
191 if(r<a->num_row()) arcb += n;
192 }
193}
194
195/* -----------------------------------------------------------------------
196 condition Version: 1.00 Date Last Changed: 1/28/93
197
198 This finds the condition number of SymMatrix.
199 ----------------------------------------------------------------------- */
200
201double condition(const HepSymMatrix &hm)
202{
203 HepSymMatrix mcopy=hm;
204 diagonalize(&mcopy);
205 double max,min;
206 max=min=fabs(mcopy(1,1));
207
208 int n = mcopy.num_row();
209 HepMatrix::mIter mii = mcopy.m.begin() + 2;
210 for (int i=2; i<=n; i++) {
211 if (max<fabs(*mii)) max=fabs(*mii);
212 if (min>fabs(*mii)) min=fabs(*mii);
213 if(i<n) mii += i+1;
214 }
215 return max/min;
216}
217
218/* -----------------------------------------------------------------------
219 diag_step Version: 1.00 Date Last Changed: 1/28/93
220
221 This does a Implicit symmetric QR step with Wilkinson Shift. See
222 algorithm 8.2.2 in Golub and Van Loan. begin and end mark the submatrix
223 of t to do the QR step on, the matrix runs from t(begin,begin) to
224 t(end,end). Can include Matrix *U to be updated so that told = U*t*U.T();
225 ----------------------------------------------------------------------- */
226
227void diag_step(HepSymMatrix *t,int begin,int end)
228{
229 double d=(t->fast(end-1,end-1)-t->fast(end,end))/2;
230 double mu=t->fast(end,end)-t->fast(end,end-1)*t->fast(end,end-1)/
231 (d+sign(d)*sqrt(d*d+ t->fast(end,end-1)*t->fast(end,end-1)));
232 double x=t->fast(begin,begin)-mu;
233 double z=t->fast(begin+1,begin);
234 HepMatrix::mIter tkk = t->m.begin() + (begin+2)*(begin-1)/2;
235 HepMatrix::mIter tkp1k = tkk + begin;
236 HepMatrix::mIter tkp2k = tkk + 2 * begin + 1;
237 for (int k=begin;k<=end-1;k++) {
238 double c,ds;
239 givens(x,z,&c,&ds);
240
241 // This is the result of G.T*t*G, making use of the special structure
242 // of t and G. Note that since t is symmetric, only the lower half
243 // needs to be updated. Equations were gotten from maple.
244
245 if (k!=begin)
246 {
247 *(tkk-1)= *(tkk-1)*c-(*(tkp1k-1))*ds;
248 *(tkp1k-1)=0;
249 }
250 double ap=(*tkk);
251 double bp=(*tkp1k);
252 double aq=(*tkp1k+1);
253 (*tkk)=ap*c*c-2*c*bp*ds+aq*ds*ds;
254 (*tkp1k)=c*ap*ds+bp*c*c-bp*ds*ds-ds*aq*c;
255 (*(tkp1k+1))=ap*ds*ds+2*c*bp*ds+aq*c*c;
256 if (k<end-1)
257 {
258 double bq=(*(tkp2k+1));
259 (*tkp2k)=-bq*ds;
260 (*(tkp2k+1))=bq*c;
261 x=(*tkp1k);
262 z=(*tkp2k);
263 tkk += k+1;
264 tkp1k += k+2;
265 }
266 if(k<end-2) tkp2k += k+3;
267 }
268}
269
270void diag_step(HepSymMatrix *t,HepMatrix *u,int begin,int end)
271{
272 double d=(t->fast(end-1,end-1)-t->fast(end,end))/2;
273 double mu=t->fast(end,end)-t->fast(end,end-1)*t->fast(end,end-1)/
274 (d+sign(d)*sqrt(d*d+ t->fast(end,end-1)*t->fast(end,end-1)));
275 double x=t->fast(begin,begin)-mu;
276 double z=t->fast(begin+1,begin);
277 HepMatrix::mIter tkk = t->m.begin() + (begin+2)*(begin-1)/2;
278 HepMatrix::mIter tkp1k = tkk + begin;
279 HepMatrix::mIter tkp2k = tkk + 2 * begin + 1;
280 for (int k=begin;k<=end-1;k++) {
281 double c,ds;
282 givens(x,z,&c,&ds);
283 col_givens(u,c,ds,k,k+1);
284
285 // This is the result of G.T*t*G, making use of the special structure
286 // of t and G. Note that since t is symmetric, only the lower half
287 // needs to be updated. Equations were gotten from maple.
288
289 if (k!=begin) {
290 *(tkk-1)= (*(tkk-1))*c-(*(tkp1k-1))*ds;
291 *(tkp1k-1)=0;
292 }
293 double ap=(*tkk);
294 double bp=(*tkp1k);
295 double aq=(*(tkp1k+1));
296 (*tkk)=ap*c*c-2*c*bp*ds+aq*ds*ds;
297 (*tkp1k)=c*ap*ds+bp*c*c-bp*ds*ds-ds*aq*c;
298 (*(tkp1k+1))=ap*ds*ds+2*c*bp*ds+aq*c*c;
299 if (k<end-1) {
300 double bq=(*(tkp2k+1));
301 (*tkp2k)=-bq*ds;
302 (*(tkp2k+1))=bq*c;
303 x=(*tkp1k);
304 z=(*(tkp2k));
305 tkk += k+1;
306 tkp1k += k+2;
307 }
308 if(k<end-2) tkp2k += k+3;
309 }
310}
311
312/* -----------------------------------------------------------------------
313 diagonalize Version: 1.00 Date Last Changed: 1/28/93
314
315 This subroutine diagonalizes a symmatrix using algorithm 8.2.3 in Golub &
316 Van Loan. It returns the matrix U so that sold = U*sdiag*U.T
317 ----------------------------------------------------------------------- */
319{
320 const double tolerance = 1e-12;
321 HepMatrix u= tridiagonal(hms);
322 int begin=1;
323 int end=hms->num_row();
324 while(begin!=end)
325 {
326 HepMatrix::mIter sii = hms->m.begin() + (begin+2)*(begin-1)/2;
327 HepMatrix::mIter sip1i = sii + begin;
328 for (int i=begin;i<=end-1;i++) {
329 if (fabs(*sip1i)<=
330 tolerance*(fabs(*sii)+fabs(*(sip1i+1)))) {
331 (*sip1i)=0;
332 }
333 if(i<end-1) {
334 sii += i+1;
335 sip1i += i+2;
336 }
337 }
338 while(begin<end && hms->fast(begin+1,begin) ==0) begin++;
339 while(end>begin && hms->fast(end,end-1) ==0) end--;
340 if (begin!=end)
341 diag_step(hms,&u,begin,end);
342 }
343 return u;
344}
345
346/* -----------------------------------------------------------------------
347 house Version: 1.00 Date Last Changed: 1/28/93
348
349 This return a Householder Vector to zero the elements in column col,
350 from row+1 to a.num_row().
351 ----------------------------------------------------------------------- */
352
353HepVector house(const HepSymMatrix &a,int row,int col)
354{
355 HepVector v(a.num_row()-row+1);
356/* not tested */
357 HepMatrix::mIter vp = v.m.begin();
358 HepMatrix::mcIter aci = a.m.begin() + col * (col - 1) / 2 + row - 1;
359 int i;
360 for (i=row;i<=col;i++) {
361 (*(vp++))=(*(aci++));
362 }
363 for (;i<=a.num_row();i++) {
364 (*(vp++))=(*aci);
365 aci += i;
366 }
367 v(1)+=sign(a(row,col))*v.norm();
368 return v;
369}
370
371HepVector house(const HepMatrix &a,int row,int col)
372{
373 HepVector v(a.num_row()-row+1);
374/* not tested */
375 int n = a.num_col();
376 HepMatrix::mcIter aic = a.m.begin() + (row - 1) * n + (col - 1) ;
377 HepMatrix::mIter vp = v.m.begin();
378 for (int i=row;i<=a.num_row();i++) {
379 (*(vp++))=(*aic);
380 aic += n;
381 }
382 v(1)+=sign(a(row,col))*v.norm();
383 return v;
384}
385
386/* -----------------------------------------------------------------------
387 house_with_update Version: 1.00 Date Last Changed: 1/28/93
388
389 This returns the householder vector as in house, and it also changes
390 A to be PA. (It is slightly more efficient than calling house, followed
391 by calling row_house). If you include the optional Matrix *house_vector,
392 then the householder vector is stored in house_vector(row,col) to
393 house_vector(a->num_row(),col).
394 ----------------------------------------------------------------------- */
395
396void house_with_update(HepMatrix *a,int row,int col)
397{
398 HepVector v(a->num_row()-row+1);
399/* not tested */
400 HepMatrix::mIter vp = v.m.begin();
401 int n = a->num_col();
402 HepMatrix::mIter arc = a->m.begin() + (row-1) * n + (col-1);
403 int r;
404 for (r=row;r<=a->num_row();r++) {
405 (*(vp++))=(*arc);
406 if(r<a->num_row()) arc += n;
407 }
408 double normsq=v.normsq();
409 double norm=sqrt(normsq);
410 normsq-=v(1)*v(1);
411 v(1)+=sign((*a)(row,col))*norm;
412 normsq+=v(1)*v(1);
413 (*a)(row,col)=-sign((*a)(row,col))*norm;
414 if (row<a->num_row()) {
415 arc = a->m.begin() + row * n + (col-1);
416 for (r=row+1;r<=a->num_row();r++) {
417 (*arc)=0;
418 if(r<a->num_row()) arc += n;
419 }
420 row_house(a,v,normsq,row,col+1);
421 }
422}
423
424void house_with_update(HepMatrix *a,HepMatrix *v,int row,int col)
425{
426 double normsq=0;
427 int nv = v->num_col();
428 int na = a->num_col();
429 HepMatrix::mIter vrc = v->m.begin() + (row-1) * nv + (col-1);
430 HepMatrix::mIter arc = a->m.begin() + (row-1) * na + (col-1);
431 int r;
432 for (r=row;r<=a->num_row();r++) {
433 (*vrc)=(*arc);
434 normsq+=(*vrc)*(*vrc);
435 if(r<a->num_row()) {
436 vrc += nv;
437 arc += na;
438 }
439 }
440 double norm=sqrt(normsq);
441 vrc = v->m.begin() + (row-1) * nv + (col-1);
442 normsq-=(*vrc)*(*vrc);
443 (*vrc)+=sign((*a)(row,col))*norm;
444 normsq+=(*vrc)*(*vrc);
445 (*a)(row,col)=-sign((*a)(row,col))*norm;
446 if (row<a->num_row()) {
447 arc = a->m.begin() + row * na + (col-1);
448 for (r=row+1;r<=a->num_row();r++) {
449 (*arc)=0;
450 if(r<a->num_row()) arc += na;
451 }
452 row_house(a,*v,normsq,row,col+1,row,col);
453 }
454}
455/* -----------------------------------------------------------------------
456 house_with_update2 Version: 1.00 Date Last Changed: 1/28/93
457
458 This is a variation of house_with_update for use with tridiagonalization.
459 It only updates column number col in a SymMatrix.
460 ----------------------------------------------------------------------- */
461
462void house_with_update2(HepSymMatrix *a,HepMatrix *v,int row,int col)
463{
464 double normsq=0;
465 int nv = v->num_col();
466 HepMatrix::mIter vrc = v->m.begin() + (row-1) * nv + (col-1);
467 HepMatrix::mIter arc = a->m.begin() + (row-1) * row / 2 + (col-1);
468 int r;
469 for (r=row;r<=a->num_row();r++)
470 {
471 (*vrc)=(*arc);
472 normsq+=(*vrc)*(*vrc);
473 if(r<a->num_row()) {
474 arc += r;
475 vrc += nv;
476 }
477 }
478 double norm=sqrt(normsq);
479 vrc = v->m.begin() + (row-1) * nv + (col-1);
480 arc = a->m.begin() + (row-1) * row / 2 + (col-1);
481 (*vrc)+=sign(*arc)*norm;
482 (*arc)=-sign(*arc)*norm;
483 arc += row;
484 for (r=row+1;r<=a->num_row();r++) {
485 (*arc)=0;
486 if(r<a->num_row()) arc += r;
487 }
488}
489
490/* -----------------------------------------------------------------------
491 inverse Version: 1.00 Date Last Changed: 2/9/93
492
493 This calculates the inverse of a square matrix. Note that this is
494 often not what you really want to do. Often, you really want solve or
495 backsolve, which can be faster at calculating (e.g. you want the inverse
496 to calculate A^-1*c where c is a vector. Then this is just solve(A,c))
497
498 If A is not need after the calculation, you can call this with *A. A will
499 be destroyed, but the inverse will be calculated quicker.
500 ----------------------------------------------------------------------- */
501
503{
504 HepMatrix Atemp=A;
505 return qr_inverse(&Atemp);
506}
507
509{
510 if (A->num_row()!=A->num_col()) {
511 HepGenMatrix::error("qr_inverse: The matrix is not square.");
512 }
513 HepMatrix QT=qr_decomp(A).T();
514 back_solve(*A,&QT);
515 return QT;
516}
517
518/* -----------------------------------------------------------------------
519 Version: 1.00 Date Last Changed: 5/26/93
520
521 This takes a set of lines described by Xi=Ai*t+Bi and finds the point P
522 that is closest to the lines in the least squares sense. n is the
523 number of lines, and A and B are pointers to arrays of the Vectors Ai
524 and Bi. The array runs from 0 to n-1.
525 ----------------------------------------------------------------------- */
526
527HepVector min_line_dist(const HepVector *const A, const HepVector *const B,
528 int n)
529{
530 // For (P-(A t +B))^2 minimum, we have tmin=dot(A,P-B)/A.normsq(). So
531 // To minimize distance, we want sum_i (P-(Ai tmini +Bi))^2 minimum. This
532 // is solved by having
533 // (sum_i k Ai*Ai.T +1) P - (sum_i k dot(Ai,Bi) Ai + Bi) = 0
534 // where k=1-2/Ai.normsq
535 const double small = 1e-10; // Small number
536 HepSymMatrix C(3,0),I(3,1);
537 HepVector D(3,0);
538 double t;
539 for (int i=0;i<n;i++)
540 {
541 if (fabs(t=A[i].normsq())<small) {
542 C += I;
543 D += B[i];
544 } else {
545 C += vT_times_v(A[i])*(1-2/t)+I;
546 D += dot(A[i],B[i])*(1-2/t)*A[i]+B[i];
547 }
548 }
549 return qr_solve(C,D);
550}
551
552/* -----------------------------------------------------------------------
553 qr_decomp Version: 1.00 Date Last Changed: 1/28/93
554
555 This does a Householder QR decomposition of the passed matrix. The
556 matrix does not have to be square, but the number of rows needs to be
557 >= number of columns. If A is a mxn matrix, Q is mxn and R is nxn.
558 R is returned in the upper left part of A. qr_decomp with a second
559 matrix changes A to R, and returns a set of householder vectors.
560
561 Algorithm is from Golub and Van Loan 5.15.
562 ----------------------------------------------------------------------- */
563
565{
566 HepMatrix hsm(A->num_row(),A->num_col());
567 qr_decomp(A,&hsm);
568 // Try to make Q diagonal
569 // HepMatrix Q(A->num_row(),A->num_col(),1);
570 HepMatrix Q(A->num_row(),A->num_row(),1);
571 for (int j=hsm.num_col();j>=1;--j)
572 row_house(&Q,hsm,j,j,j,j);
573 return Q;
574}
575
576/* -----------------------------------------------------------------------
577 row_givens Version: 1.00 Date Last Changed: 1/28/93
578
579 This algorithm performs a Givens rotation on the left. Given c and s
580 and k1 and k2, this is like forming G= identity except for row k1 and
581 k2 where G(k1,k1)=c, G(k1,k2)=s, G(k2,k1)=-s, G(k2,k2)=c. It replaces
582 A with G.T()*A. A variation allows you to express col_min and col_max,
583 and then only the submatrix of A from (1,col_min) to (num_row(),col_max)
584 are updated. This is algorithm 5.1.6 in Golub and Van Loan.
585 ----------------------------------------------------------------------- */
586
587void row_givens(HepMatrix *A, double c,double ds,
588 int k1, int k2, int col_min, int col_max) {
589 /* not tested */
590 if (col_max==0) col_max = A->num_col();
591 int n = A->num_col();
592 HepMatrix::mIter Ak1j = A->m.begin() + (k1-1) * n + (col_min-1);
593 HepMatrix::mIter Ak2j = A->m.begin() + (k2-1) * n + (col_min-1);
594 for (int j=col_min;j<=col_max;j++) {
595 double tau1=(*Ak1j); double tau2=(*Ak2j);
596 (*(Ak1j++))=c*tau1-ds*tau2;(*(Ak2j++))=ds*tau1+c*tau2;
597 }
598}
599
600/* -----------------------------------------------------------------------
601 row_house Version: 1.00 Date Last Changed: 1/28/93
602
603 This replaces A with P*A where P=I-2v*v.T/(v.T*v). If row and col are
604 not one, then it only acts on the subpart of A, from A(row,col) to
605 A(A.num_row(),A.num_row()). For use with house, can pass V as a matrix.
606 Then row_start and col_start describe where the vector lies. It is
607 assumed to run from V(row_start,col_start) to
608 V(row_start+A.num_row()-row,col_start).
609 Since typically row_house comes after house, and v.normsq is calculated
610 in house, it is passed as a arguement. Also supplied without vnormsq.
611 ----------------------------------------------------------------------- */
612
613void row_house(HepMatrix *a,const HepVector &v,double vnormsq,
614 int row, int col) {
615 double beta=-2/vnormsq;
616
617 // This is a fast way of calculating w=beta*A.sub(row,n,col,n).T()*v
618
619 HepVector w(a->num_col()-col+1,0);
620/* not tested */
621 int na = a->num_col();
622 HepMatrix::mIter wptr = w.m.begin();
623 HepMatrix::mIter arcb = a->m.begin() + (row-1) * na + (col-1);
624 int c;
625 for (c=col;c<=a->num_col();c++) {
626 HepMatrix::mcIter vp = v.m.begin();
627 HepMatrix::mIter arc = arcb;
628 for (int r=row;r<=a->num_row();r++) {
629 (*wptr)+=(*arc)*(*(vp++));
630 if(r<a->num_row()) arc += na;
631 }
632 wptr++;
633 arcb++;
634 }
635 w*=beta;
636
637 // Fast way of calculating A.sub=A.sub+v*w.T()
638
639 arcb = a->m.begin() + (row-1) * na + (col-1);
640 HepMatrix::mcIter vp = v.m.begin();
641 for (int r=row; r<=a->num_row();r++) {
642 HepMatrix::mIter wptr2 = w.m.begin();
643 HepMatrix::mIter arc = arcb;
644 for (c=col;c<=a->num_col();c++) {
645 (*(arc++))+=(*vp)*(*(wptr2++));
646 }
647 vp++;
648 if(r<a->num_row()) arcb += na;
649 }
650}
651
652void row_house(HepMatrix *a,const HepMatrix &v,double vnormsq,
653 int row, int col, int row_start, int col_start) {
654 double beta=-2/vnormsq;
655
656 // This is a fast way of calculating w=beta*A.sub(row,n,col,n).T()*v
657 HepVector w(a->num_col()-col+1,0);
658 int na = a->num_col();
659 int nv = v.num_col();
660 HepMatrix::mIter wptr = w.m.begin();
661 HepMatrix::mIter arcb = a->m.begin() + (row-1) * na + (col-1);
662 HepMatrix::mcIter vpcb = v.m.begin() + (row_start-1) * nv + (col_start-1);
663 int c;
664 for (c=col;c<=a->num_col();c++) {
665 HepMatrix::mIter arc = arcb;
666 HepMatrix::mcIter vpc = vpcb;
667 for (int r=row;r<=a->num_row();r++) {
668 (*wptr)+=(*arc)*(*vpc);
669 if(r<a->num_row()) {
670 arc += na;
671 vpc += nv;
672 }
673 }
674 wptr++;
675 arcb++;
676 }
677 w*=beta;
678
679 arcb = a->m.begin() + (row-1) * na + (col-1);
680 HepMatrix::mcIter vpc = v.m.begin() + (row_start-1) * nv + (col_start-1);
681 for (int r=row; r<=a->num_row();r++) {
682 HepMatrix::mIter arc = arcb;
683 HepMatrix::mIter wptr2 = w.m.begin();
684 for (c=col;c<=a->num_col();c++) {
685 (*(arc++))+=(*vpc)*(*(wptr2++));
686 }
687 if(r<a->num_row()) {
688 arcb += na;
689 vpc += nv;
690 }
691 }
692}
693
694/* -----------------------------------------------------------------------
695 solve Version: 1.00 Date Last Changed: 2/9/93
696
697 This solves the system A*x=b where A is not upper triangular, but it
698 must have full rank. If A is not square, then this is solved in the least
699 squares sense. Has a variation that works for b a matrix with each column
700 being a different vector. If A is not needed after this call, you can
701 call solve with *A. This will destroy A, but it will run faster.
702 ----------------------------------------------------------------------- */
703
705{
706 HepMatrix temp = A;
707 return qr_solve(&temp,b);
708}
709
711{
712 HepMatrix Q=qr_decomp(A);
713 // Quick way to to Q.T*b.
714 HepVector b2(Q.num_col(),0);
715 HepMatrix::mIter b2r = b2.m.begin();
716 HepMatrix::mIter Qr = Q.m.begin();
717 int n = Q.num_col();
718 for (int r=1;r<=b2.num_row();r++) {
719 HepMatrix::mcIter bc = b.m.begin();
720 HepMatrix::mIter Qcr = Qr;
721 for (int c=1;c<=b.num_row();c++) {
722 *b2r += (*Qcr) * (*(bc++));
723 if(c<b.num_row()) Qcr += n;
724 }
725 b2r++;
726 Qr++;
727 }
728 back_solve(*A,&b2);
729 return b2;
730}
731
733{
734 HepMatrix temp = A;
735 return qr_solve(&temp,b);
736}
737
739{
740 HepMatrix Q=qr_decomp(A);
741 // Quick way to to Q.T*b.
742 HepMatrix b2(Q.num_col(),b.num_col(),0);
743 int nb = b.num_col();
744 int nq = Q.num_col();
745 HepMatrix::mcIter b1i = b.m.begin();
746 HepMatrix::mIter b21i = b2.m.begin();
747 for (int i=1;i<=b.num_col();i++) {
748 HepMatrix::mIter Q1r = Q.m.begin();
749 HepMatrix::mIter b2ri = b21i;
750 for (int r=1;r<=b2.num_row();r++) {
751 HepMatrix::mIter Qcr = Q1r;
752 HepMatrix::mcIter bci = b1i;
753 for (int c=1;c<=b.num_row();c++) {
754 *b2ri += (*Qcr) * (*bci);
755 if(c<b.num_row()) {
756 Qcr += nq;
757 bci += nb;
758 }
759 }
760 Q1r++;
761 if(r<b2.num_row()) b2ri += nb;
762 }
763 b1i++;
764 b21i++;
765 }
766 back_solve(*A,&b2);
767 return b2;
768}
769
770/* -----------------------------------------------------------------------
771 tridiagonal Version: 1.00 Date Last Changed: 1/28/93
772
773 This does a Householder tridiagonalization. It takes a symmetric matrix
774 A and changes it to A=U*T*U.T.
775 ----------------------------------------------------------------------- */
776
778{
779 int nh = hsm->num_col();
780 for (int k=1;k<=a->num_col()-2;k++) {
781
782 // If this row is already in tridiagonal form, we can skip the
783 // transformation.
784
785 double scale=0;
786 HepMatrix::mIter ajk = a->m.begin() + k * (k+5) / 2;
787 int j;
788 for (j=k+2;j<=a->num_row();j++) {
789 scale+=fabs(*ajk);
790 if(j<a->num_row()) ajk += j;
791 }
792 if (scale ==0) {
793 HepMatrix::mIter hsmjkp = hsm->m.begin() + k * (nh+1) - 1;
794 for (j=k+1;j<=hsm->num_row();j++) {
795 *hsmjkp = 0;
796 if(j<hsm->num_row()) hsmjkp += nh;
797 }
798 } else {
799 house_with_update2(a,hsm,k+1,k);
800 double normsq=0;
801 HepMatrix::mIter hsmrptrkp = hsm->m.begin() + k * (nh+1) - 1;
802 int rptr;
803 for (rptr=k+1;rptr<=hsm->num_row();rptr++) {
804 normsq+=(*hsmrptrkp)*(*hsmrptrkp);
805 if(rptr<hsm->num_row()) hsmrptrkp += nh;
806 }
807 HepVector p(a->num_row()-k,0);
808 rptr=k+1;
809 HepMatrix::mIter pr = p.m.begin();
810 int r;
811 for (r=1;r<=p.num_row();r++) {
812 HepMatrix::mIter hsmcptrkp = hsm->m.begin() + k * (nh+1) - 1;
813 int cptr;
814 for (cptr=k+1;cptr<=rptr;cptr++) {
815 (*pr)+=a->fast(rptr,cptr)*(*hsmcptrkp);
816 if(cptr<a->num_col()) hsmcptrkp += nh;
817 }
818 for (;cptr<=a->num_col();cptr++) {
819 (*pr)+=a->fast(cptr,rptr)*(*hsmcptrkp);
820 if(cptr<a->num_col()) hsmcptrkp += nh;
821 }
822 (*pr)*=2/normsq;
823 rptr++;
824 pr++;
825 }
826 double pdotv=0;
827 pr = p.m.begin();
828 hsmrptrkp = hsm->m.begin() + k * (nh+1) - 1;
829 for (r=1;r<=p.num_row();r++) {
830 pdotv+=(*(pr++))*(*hsmrptrkp);
831 if(r<p.num_row()) hsmrptrkp += nh;
832 }
833 pr = p.m.begin();
834 hsmrptrkp = hsm->m.begin() + k * (nh+1) - 1;
835 for (r=1;r<=p.num_row();r++) {
836 (*(pr++))-=pdotv*(*hsmrptrkp)/normsq;
837 if(r<p.num_row()) hsmrptrkp += nh;
838 }
839 rptr=k+1;
840 pr = p.m.begin();
841 hsmrptrkp = hsm->m.begin() + k * (nh+1) - 1;
842 for (r=1;r<=p.num_row();r++) {
843 int cptr=k+1;
844 HepMatrix::mIter mpc = p.m.begin();
845 HepMatrix::mIter hsmcptrkp = hsm->m.begin() + k * (nh+1) - 1;
846 for (int c=1;c<=r;c++) {
847 a->fast(rptr,cptr)-= (*hsmrptrkp)*(*(mpc++))+(*pr)*(*hsmcptrkp);
848 cptr++;
849 if(c<r) hsmcptrkp += nh;
850 }
851 pr++;
852 rptr++;
853 if(r<p.num_row()) hsmrptrkp += nh;
854 }
855 }
856 }
857}
858
860{
861 HepMatrix U(a->num_row(),a->num_col(),1);
862 if (a->num_col()>2)
863 {
864 HepMatrix hsm(a->num_col(),a->num_col()-2,0);
865 tridiagonal(a,&hsm);
866 for (int j=hsm.num_col();j>=1;--j) {
867 row_house(&U,hsm,j,j,j,j);
868 }
869 }
870 return U;
871}
872
873void col_house(HepMatrix *a,const HepMatrix &v,int row,int col,
874 int row_start,int col_start)
875{
876 double normsq=0;
877 for (int i=row_start;i<=row_start+a->num_row()-row;i++)
878 normsq+=v(i,col)*v(i,col);
879 col_house(a,v,normsq,row,col,row_start,col_start);
880}
881
882void givens(double a, double b, double *c, double *ds)
883{
884 if (b ==0) { *c=1; *ds=0; }
885 else {
886 if (fabs(b)>fabs(a)) {
887 double tau=-a/b;
888 *ds=1/sqrt(1+tau*tau);
889 *c=(*ds)*tau;
890 } else {
891 double tau=-b/a;
892 *c=1/sqrt(1+tau*tau);
893 *ds=(*c)*tau;
894 }
895 }
896}
897
899{
900 for (int i=1;i<=A->num_col();i++)
901 house_with_update(A,hsm,i,i);
902}
903
904void row_house(HepMatrix *a,const HepMatrix &v,int row,int col,
905 int row_start,int col_start)
906{
907 double normsq=0;
908 int end = row_start+a->num_row()-row;
909 for (int i=row_start; i<=end; i++)
910 normsq += v(i,col)*v(i,col);
911 // If v is 0, then we can skip doing row_house.
912 if (normsq !=0)
913 row_house(a,v,normsq,row,col,row_start,col_start);
914}
915
916} // namespace CLHEP
std::vector< double, Alloc< double, 25 > >::const_iterator mcIter
Definition: GenMatrix.h:74
std::vector< double, Alloc< double, 25 > >::iterator mIter
Definition: GenMatrix.h:73
static void error(const char *s)
Definition: GenMatrix.cc:70
virtual int num_col() const
Definition: Matrix.cc:120
virtual int num_row() const
Definition: Matrix.cc:118
int num_row() const
int num_col() const
const double & fast(int row, int col) const
double norm() const
virtual int num_row() const
Definition: Vector.cc:116
double normsq() const
void col_house(HepMatrix *a, const HepMatrix &v, double vnormsq, int row, int col, int row_start, int col_start)
void tridiagonal(HepSymMatrix *a, HepMatrix *hsm)
HepVector qr_solve(const HepMatrix &A, const HepVector &b)
HepSymMatrix vT_times_v(const HepVector &v)
Definition: SymMatrix.cc:539
void house_with_update2(HepSymMatrix *a, HepMatrix *v, int row=1, int col=1)
double norm(const HepGenMatrix &m)
Definition: GenMatrix.cc:54
HepMatrix qr_inverse(const HepMatrix &A)
void house_with_update(HepMatrix *a, int row=1, int col=1)
void back_solve(const HepMatrix &R, HepVector *b)
Definition: MatrixLinear.cc:63
void qr_decomp(HepMatrix *A, HepMatrix *hsm)
double dot(const HepVector &v1, const HepVector &v2)
Definition: Vector.cc:542
HepVector house(const HepMatrix &a, int row=1, int col=1)
HepVector min_line_dist(const HepVector *const A, const HepVector *const B, int n)
void row_givens(HepMatrix *A, double c, double s, int k1, int k2, int col_min=1, int col_max=0)
void givens(double a, double b, double *c, double *s)
void col_givens(HepMatrix *A, double c, double s, int k1, int k2, int row_min=1, int row_max=0)
void row_house(HepMatrix *a, const HepVector &v, double vnormsq, int row=1, int col=1)
double condition(const HepSymMatrix &m)
HepMatrix diagonalize(HepSymMatrix *s)
void diag_step(HepSymMatrix *t, int begin, int end)
Definition: excDblThrow.cc:8
Definition: excDblThrow.cc:17