Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 5463 was 5449, checked in by bensch, 19 years ago

orxonox/trunk: Jacobi-reloaded

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