Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 5490 was 5490, checked in by patrick, 18 years ago

orxonox/trunk/src/lib/collision: heavy work on the jacobi function

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