Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/trunk/src/lib/collision_detection/lin_alg.h @ 5488

Last change on this file since 5488 was 5488, checked in by patrick, 19 years ago

orxonox/trunk/src/lib/cd: woking on the jacobi matrix decomposition algorithm

File size: 14.8 KB
Line 
1/*!
2 * @file lin_alg.h
3  *  Definition of some important linear algebra formulas
4
5    compute the eigenpairs (eigenvalues and eigenvectors) of a real symmetric matrix "A" by the Jacobi method
6 */
7
8
9
10/************************************************************
11* This subroutine computes all eigenvalues and eigenvectors *
12* of a real symmetric square matrix A(N,N). On output, ele- *
13* ments of A above the diagonal are destroyed. D(N) returns *
14* the eigenvalues of matrix A. V(N,N) contains, on output,  *
15* the eigenvectors of A by columns. THe normalization to    *
16* unity is made by main program before printing results.    *
17* NROT returns the number of Jacobi matrix rotations which  *
18* were required.                                            *
19* --------------------------------------------------------- *
20* Ref.:"NUMERICAL RECIPES IN FORTRAN, Cambridge University  *
21*       Press, 1986, chap. 11, pages 346-348".              *
22*                                                           *
23*                         C++ version by J-P Moreau, Paris. *
24************************************************************/
25void JacobI(float **A, float *D, float **V, int *NROT) {
26
27int N = 3;
28
29float  *B, *Z;
30double  c=0.0f, g=0.0f, h=0.0f, s=0.0f, sm=0.0f, t=0.0f, tau=0.0f, theta=0.0f, tresh=0.0f;
31int     i=0,j=0,ip=0,iq=0;
32
33  //allocate vectors B, Z
34
35  //B = (float *) calloc(100, 32);
36  //Z = (float *) calloc(100, 32);
37  B = new float[N];
38  Z = new float[N];
39
40
41  for( ip = 0; ip < 3; ip++) {  //initialize V to identity matrix
42    for( iq = 0; iq < 3; iq++)
43      V[ip][iq] = 0.0f;
44    V[ip][ip] = 1.0f;
45  }
46  for( ip = 1; ip <= N; ip++) {
47    B[ip] = A[ip][ip];
48    D[ip] = B[ip];
49    Z[ip] = 0;
50  }
51
52  *NROT = 0;
53  // make maximaly 50 iterations
54  for( i = 1; i <= 50; i++) {
55    sm = 0;
56
57    for( ip = 0; ip < 2; ip++)    //sum off-diagonal elements
58      for( iq = ip + 1; iq < 3; iq++)
59        sm=sm+fabs(A[ip][iq]);
60
61    if(sm == 0)
62    {
63      free(B);
64      free(Z);
65      return;       //normal return
66    }
67      tresh=0.2*sm*sm;
68    for (ip=0; ip<2; ip++) {
69      for (iq=ip+1; iq<3; iq++) {
70        g=100*fabs(A[ip][iq]);
71// after 4 sweeps, skip the rotation if the off-diagonal element is small
72        if ((i > 4) && (fabs(D[ip])+g == fabs(D[ip])) && (fabs(D[iq])+g == fabs(D[iq])))
73          A[ip][iq]=0;
74        else if (fabs(A[ip][iq]) > tresh) {
75          h=D[iq]-D[ip];
76          if (fabs(h)+g == fabs(h))
77            t=A[ip][iq]/h;
78          else {
79            theta=0.5*h/A[ip][iq];
80            t=1/(fabs(theta)+sqrt(1.0+theta*theta));
81            if (theta < 0)  t=-t;
82          }
83          c=1.0/sqrt(1.0+t*t);
84          s=t*c;
85          tau=s/(1.0+c);
86          h=t*A[ip][iq];
87          Z[ip] -= h;
88          Z[iq] += h;
89          D[ip] -= h;
90          D[iq] += h;
91          A[ip][iq]=0;
92          for (j=0; j<ip; j++) {
93            g=A[j][ip];
94            h=A[j][iq];
95            A[j][ip] = g-s*(h+g*tau);
96            A[j][iq] = h+s*(g-h*tau);
97          }
98          for (j=ip+1; j<iq; j++) {
99            g=A[ip][j];
100            h=A[j][iq];
101            A[ip][j] = g-s*(h+g*tau);
102            A[j][iq] = h+s*(g-h*tau);
103          }
104          for (j=iq+1; j<=N; j++) {
105            g=A[ip][j];
106            h=A[iq][j];
107            A[ip][j] = g-s*(h+g*tau);
108            A[iq][j] = h+s*(g-h*tau);
109          }
110          for (j=0; j<3; j++) {
111            g=V[j][ip];
112            h=V[j][iq];
113            V[j][ip] = g-s*(h+g*tau);
114            V[j][iq] = h+s*(g-h*tau);
115          }
116          *NROT=*NROT+1;
117        } //end ((i.gt.4)...else if
118      } // main iq loop
119    } // main ip loop
120    for (ip=0; ip<3; ip++) {
121      B[ip] += Z[ip];
122      D[ip]=B[ip];
123      Z[ip]=0;
124    }
125  } //end of main i loop
126//  printf("\n 50 iterations !\n");
127  free(B);
128  free(Z);
129  return;  //too many iterations
130}
131
132
133
134
135
136#include "abstract_model.h"
137
138#include <stdio.h>
139#include <math.h>
140
141#define NDIM 3
142
143
144typedef float MatrixX[3][3];
145
146//
147// class "EVJacobi" for computing the eigenpairs
148// (members)
149//   ndim  int    ...  dimension
150//       "ndim" must satisfy 1 < ndim < NDIM
151//   ("NDIM" is given above).
152//   a     double [NDIM][NDIM] ...  matrix A
153//   aa    double ...  the square root of
154//                  (1/2) x (the sum of the off-diagonal elements squared)
155//   ev    double [NDIM] ...  eigenvalues
156//   evec  double [NDIM][NDIM] ... eigenvectors
157//       evec[i][k], i=1,2,...,ndim are the elements of the eigenvector
158//       corresponding to the k-th eigenvalue ev[k]
159//   vec   double [NDIM][NDIM] ... the 2-dimensional array where the matrix elements are stored
160//   lSort     int      ...
161//       If lSort = 1, sort the eigenvalues d(i) in the descending order, i.e.,
162//                       ev[1] >= ev[2] >= ... >= ev[ndim], and
163//       if lSort = 0, in the ascending order, i.e.,
164//                       ev[1] <= ev[2] <= ... <= ev[ndim].
165//   lMatSize  int      ...  If 1 < ndim < NDIM, lMatSize = 1
166//                            otherwise, lMatSize = 0
167//   p     int [NDIM]    ...  index vector for sorting the eigenvalues
168// (public member functions)
169//   setMatrix          void ...  give the matrix A
170//   getEigenValue      void ...  get the eigenvalues
171//   getEigenVector     void ...  get the eigenvectors
172//   sortEigenpair      void ...  sort the eigenpairs
173// (private member functions)
174//   ComputeEigenpair   void ...  compute the eigenpairs
175//   matrixUpdate       void ...  each step of the Jacobi method, i.e.,
176//                          update of the matrix A by Givens' transform.
177//   getP               void ...  get the index vector p, i.e., sort the eigenvalues.
178//   printMatrix        void ...  print the elements of the matrix A.
179//
180
181class EVJacobi
182{
183  public:
184    void setMatrix(int, double [][NDIM], int, int);
185    void getEigenValue(double []);
186    void getEigenVector(double [][NDIM]);
187    void sortEigenpair(int);
188
189  private:
190    void ComputeEigenpair(int);
191    void matrixUpdate();
192    void getP();
193    void printMatrix();
194
195  private:
196    double a[NDIM][NDIM], aa, ev[NDIM], evec[NDIM][NDIM], vec[NDIM][NDIM];
197    int ndim, lSort, p[NDIM], lMatSize;
198};
199
200//------------public member function of the class "EVJacobi"------------------------------
201//
202// give the dimension "ndim" and the matrix "A" and compute the eigenpairs
203// (input)
204// ndim0    int      ... dimension
205// a0     double[][NDIM]  matrix A
206// lSort0  int      ... lSort
207//       If lSort = 1, sort the eigenvalues d(i) in the descending order, i.e.,
208//                       ev[1] >= ev[2] >= ... >= ev[ndim], and
209//       if lSort = 0, in the ascending order, i.e.,
210//                       ev[1] <= ev[2] <= ... <= ev[ndim].
211// l_print  int      ...
212//       If l_print = 1, print the matrices during the iterations.
213//
214void EVJacobi::setMatrix(int ndim0, double a0[][NDIM], int lSort0, int l_print)
215{
216  ndim = ndim0;
217  if (ndim < NDIM && ndim > 1)
218  {
219    lMatSize = 1;
220    lSort = lSort0;
221    for (int i=1; i<=ndim; ++i)
222      for (int j=1; j<=ndim; ++j)
223        a[i][j] = a0[i][j];
224    //
225    aa = 0.0;
226    for (int i=1; i<=ndim; ++i)
227      for (int j=1; j<=i-1; ++j)
228        aa += a[i][j]*a[i][j];
229    aa = sqrt(aa);
230    //
231    ComputeEigenpair(l_print);
232    getP();
233  }
234  else
235  {
236    lMatSize = 0;
237    printf("ndim = %d\n", ndim);
238    printf("ndim must satisfy 1 < ndim < NDIM=%d\n", NDIM);
239  }
240}
241//
242// get the eigenvalues
243// (input)
244// ev0[NDIM] double ...  the array where the eigenvalues are written
245void EVJacobi::getEigenValue(double ev0[])
246{
247  for (int k=1; k<=ndim; ++k) ev0[k] = ev[p[k]];
248}
249//
250// get the eigenvectors
251// (input)
252// evec0[NDIM][NDIM] double ...  the two-dimensional array
253//   where the eigenvectors are written in such a way that
254//   evec0[k][i], i=1,2,...,ndim are the elements of the eigenvector
255//   corresponding to the k-th eigenvalue ev0[k]
256//
257void EVJacobi::getEigenVector(double evec0[][NDIM])
258{
259  for (int k=1; k<=ndim; ++k)
260    for (int i=1; i<=ndim; ++i)
261      evec0[k][i] = evec[p[k]][i];
262}
263//
264// sort the eigenpairs
265// (input)
266// lSort0  int
267//   If lSort0 = 1, the eigenvalues are sorted in the descending order, i.e.,
268//      ev0[1] >= ev0[2] >= ... >= ev0[ndim]
269//   and if lSort0 = 0, in the ascending order, i.e.,
270//      ev0[1] <= ev0[2] <= ... <= ev0[ndim]
271//
272void EVJacobi::sortEigenpair(int lSort0)
273{
274  lSort = lSort0;
275  getP();
276}
277//-------private member function of the class "EVJacobi"-----
278//
279// compute the eigenpairs
280// (input)
281// l_print  int
282//    If l_print = 1, print the matrices during the iterations.
283//
284void EVJacobi::ComputeEigenpair(int l_print)
285{
286  if (lMatSize==1)
287  {
288    if (l_print==1)
289    {
290      printf("step %d\n", 0);
291      printMatrix();
292      printf("\n");
293    }
294    //
295    double eps = 1.0e-15, epsa = eps * aa;
296    int kend = 1000, l_conv = 0;
297    //
298    for (int i=1; i<=ndim; ++i)
299      for (int j=1; j<=ndim; ++j)
300        vec[i][j] = 0.0;
301    for (int i=1; i<=ndim; ++i)
302      vec[i][i] = 1.0;
303    //
304    for (int k=1; k<=kend; ++k)
305    {
306      matrixUpdate();
307      double a1 = 0.0;
308      for (int i=1; i<=ndim; ++i)
309        for (int j=1; j<=i-1; ++j)
310          a1 += a[i][j] * a[i][j];
311      a1 = sqrt(a1);
312      if (a1 < epsa)
313      {
314        if (l_print==1)
315        {
316          printf("converged at step %d\n", k);
317          printMatrix();
318          printf("\n");
319        }
320        l_conv = 1;
321        break;
322      }
323      if (l_print==1)
324        if (k%10==0)
325      {
326        printf("step %d\n", k);
327        printMatrix();
328        printf("\n");
329      }
330    }
331    //
332    if (l_conv == 0) printf("Jacobi method not converged.\n");
333    for (int k=1; k<=ndim; ++k)
334    {
335      ev[k] = a[k][k];
336      for (int i=1; i<=ndim; ++i) evec[k][i] = vec[i][k];
337    }
338  }
339}
340//
341void EVJacobi::printMatrix()
342{
343  for (int i=1; i<=ndim; ++i)
344  {
345    for (int j=1; j<=ndim; ++j) printf("%8.1e ",a[i][j]);
346    printf("\n");
347  }
348}
349//
350void EVJacobi::matrixUpdate()
351{
352  double a_new[NDIM][NDIM], vec_new[NDIM][NDIM];
353  //
354  int p=2, q=1;
355  double amax = fabs(a[p][q]);
356  for (int i=3; i<=ndim; ++i)
357    for (int j=1; j<=i-1; ++j)
358      if (fabs(a[i][j]) > amax)
359  {
360    p = i;
361    q = j;
362    amax = fabs(a[i][j]);
363  }
364  //
365        // Givens' rotation by Rutishauser's rule
366  //
367  double z, t, c, s, u;
368  z = (a[q][q]  - a[p][p]) / (2.0 * a[p][q]);
369  t = fabs(z) + sqrt(1.0 + z*z);
370  if (z < 0.0) t = - t;
371  t = 1.0 / t;
372  c = 1.0 / sqrt(1.0 + t*t);
373  s = c * t;
374  u = s / (1.0 + c);
375  //
376  for (int i=1; i<=ndim; ++i)
377    for (int j=1; j<=ndim; ++j)
378      a_new[i][j] = a[i][j];
379  //
380  a_new[p][p] = a[p][p] - t * a[p][q];
381  a_new[q][q] = a[q][q] + t * a[p][q];
382  a_new[p][q] = 0.0;
383  a_new[q][p] = 0.0;
384  for (int j=1; j<=ndim; ++j)
385    if (j!=p && j!=q)
386  {
387    a_new[p][j] = a[p][j] - s * (a[q][j] + u * a[p][j]);
388    a_new[j][p] = a_new[p][j];
389    a_new[q][j] = a[q][j] + s * (a[p][j] - u * a[q][j]);
390    a_new[j][q] = a_new[q][j];
391  }
392  //
393  for (int i=1; i<=ndim; ++i)
394  {
395    vec_new[i][p] = vec[i][p] * c - vec[i][q] * s;
396    vec_new[i][q] = vec[i][p] * s + vec[i][q] * c;
397    for (int j=1; j<=ndim; ++j)
398      if (j!=p && j!=q) vec_new[i][j] = vec[i][j];
399  }
400  //
401  for (int i=1; i<=ndim; ++i)
402    for (int j=1; j<=ndim; ++j)
403  {
404    a[i][j] = a_new[i][j];
405    vec[i][j] = vec_new[i][j];
406  }
407}
408//
409// sort the eigenpairs
410//   If l_print=1, sort the eigenvalues in the descending order, i.e.,
411//      ev[1] >= ev[2] >= ... >= ev[ndim], and
412//   if l_print=0, in the ascending order, i.e.,
413//      ev[1] <= ev[2] <= ... <= ev[ndim].
414//
415void EVJacobi::getP()
416{
417  for (int i=1; i<=ndim; ++i) p[i] = i;
418  //
419  if (lSort==1)
420  {
421    for (int k=1; k<=ndim; ++k)
422    {
423      double emax = ev[p[k]];
424      for (int i=k+1; i<=ndim; ++i)
425      {
426        if (emax < ev[p[i]])
427        {
428          emax = ev[p[i]];
429          int pp = p[k];
430          p[k] = p[i];
431          p[i] = pp;
432        }
433      }
434    }
435  }
436  if (lSort==0)
437  {
438    for (int k=1; k<=ndim; ++k)
439    {
440      double emin = ev[p[k]];
441      for (int i=k+1; i<=ndim; ++i)
442      {
443        if (emin > ev[p[i]])
444        {
445          emin = ev[p[i]];
446          int pp = p[k];
447          p[k] = p[i];
448          p[i] = pp;
449        }
450      }
451    }
452  }
453}
454
455
456
457
458
459
460
461//  void jacobi(Matrix A, int n, sVec3D d, Matrix V, int *nRot)
462// {
463//   sVec3D  B, Z;
464//   double  c, g, h, s, sm, t, tau, theta, tresh;
465//   int     i, j, ip, iq;
466//
467//   void *vmblock1 = NULL;
468//
469//   //allocate vectors B, Z
470//   vmblock1 = vminit();
471//   //B = (float *) vmalloc(vmblock1, VEKTOR,  100, 0);
472//   //Z = (float *) vmalloc(vmblock1, VEKTOR,  100, 0);
473//
474//    //initialize V to identity matrix
475//   for(int i = 1; i <= n; i++)
476//   {
477//     for(int j = 1; j <= n; j++)
478//         V[i][j] = 0;
479//     V[i][i] = 1;
480//   }
481//
482//   for(int i = 1; i <= n; i++)
483//   {
484//     B[i] = A[i][i];
485//     D[i] = B[i];
486//     Z[i] = 0;
487//   }
488//
489//   *nRot = 0;
490//   for(int i = 1; i<=50; i++)
491//   {
492//     sm = 0;
493//     for(int k = 1; k < n; k++)    //sum off-diagonal elements
494//       for (int l = k + 1; l <= n; k++)
495//         sm = sm + fabs(A[k][l]);
496//     if ( sm == 0 )
497//     {
498//       //vmfree(vmblock1);
499//       return;       //normal return
500//     }
501//     if (i < 4)
502//       tresh = 0.2 * sm * sm;
503//     else
504//       tresh = 0;
505//     for(int k = 1; k < n; k++)
506//     {
507//       for (iq=ip+1; iq<=N; iq++) {
508//         g=100*fabs(A[ip][iq]);
509// // after 4 sweeps, skip the rotation if the off-diagonal element is small
510//         if ((i > 4) && (fabs(D[ip])+g == fabs(D[ip])) && (fabs(D[iq])+g == fabs(D[iq])))
511//           A[ip][iq]=0;
512//         else if (fabs(A[ip][iq]) > tresh) {
513//           h=D[iq]-D[ip];
514//           if (fabs(h)+g == fabs(h))
515//             t=A[ip][iq]/h;
516//           else {
517//             theta=0.5*h/A[ip][iq];
518//             t=1/(fabs(theta)+sqrt(1.0+theta*theta));
519//             if (theta < 0)  t=-t;
520//           }
521//           c=1.0/sqrt(1.0+t*t);
522//           s=t*c;
523//           tau=s/(1.0+c);
524//           h=t*A[ip][iq];
525//           Z[ip] -= h;
526//           Z[iq] += h;
527//           D[ip] -= h;
528//           D[iq] += h;
529//           A[ip][iq]=0;
530//           for (j=1; j<ip; j++) {
531//             g=A[j][ip];
532//             h=A[j][iq];
533//             A[j][ip] = g-s*(h+g*tau);
534//             A[j][iq] = h+s*(g-h*tau);
535//           }
536//           for (j=ip+1; j<iq; j++) {
537//             g=A[ip][j];
538//             h=A[j][iq];
539//             A[ip][j] = g-s*(h+g*tau);
540//             A[j][iq] = h+s*(g-h*tau);
541//           }
542//           for (j=iq+1; j<=N; j++) {
543//             g=A[ip][j];
544//             h=A[iq][j];
545//             A[ip][j] = g-s*(h+g*tau);
546//             A[iq][j] = h+s*(g-h*tau);
547//           }
548//           for (j=1; j<=N; j++) {
549//             g=V[j][ip];
550//             h=V[j][iq];
551//             V[j][ip] = g-s*(h+g*tau);
552//             V[j][iq] = h+s*(g-h*tau);
553//           }
554//           *NROT=*NROT+1;
555//         } //end ((i.gt.4)...else if
556//       } // main iq loop
557//     } // main ip loop
558//     for (ip=1; ip<=N; ip++) {
559//       B[ip] += Z[ip];
560//       D[ip]=B[ip];
561//       Z[ip]=0;
562//     }
563//   } //end of main i loop
564//   printf("\n 50 iterations !\n");
565//   vmfree(vmblock1);
566//   return;  //too many iterations
567// }
568
Note: See TracBrowser for help on using the repository browser.