Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: trying to implement my own jacobi decomposition alg since the other once didn't work… shit

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