Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: the memory requirements are lowered, some strucural changes in the bv generation

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