vmmlib  1.7.0
 All Classes Namespaces Functions Pages
jacobi_solver.hpp
1 /*
2  * Copyright (c) 2006-2014, Visualization and Multimedia Lab,
3  * University of Zurich <http://vmml.ifi.uzh.ch>,
4  * Eyescale Software GmbH,
5  * Blue Brain Project, EPFL
6  *
7  * This file is part of VMMLib <https://github.com/VMML/vmmlib/>
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions are met:
11  *
12  * Redistributions of source code must retain the above copyright notice, this
13  * list of conditions and the following disclaimer. Redistributions in binary
14  * form must reproduce the above copyright notice, this list of conditions and
15  * the following disclaimer in the documentation and/or other materials provided
16  * with the distribution. Neither the name of the Visualization and Multimedia
17  * Lab, University of Zurich nor the names of its contributors may be used to
18  * endorse or promote products derived from this software without specific prior
19  * written permission.
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #ifndef __VMML__JACOBI_SOLVER__HPP__
34 #define __VMML__JACOBI_SOLVER__HPP__
35 
36 #include <vmmlib/vmmlib.hpp>
37 
38 #include <cmath>
39 #include <cassert>
40 
41 namespace vmml
42 {
43 
44 /*
45  * This function computes the eigenvalues and eigenvectors of a 3x3 matrix.
46  *
47  * @param a matrix to be diagonalized.
48  * @param d eigenvalues of A.
49  * @param v matrix whose columns are the normalized eigenvectors of A.
50  * @param rotationCount number of Jacobi rotations required.
51  * @return true if the transformation has been done. False if not.
52  *
53  *
54  * modified from numerical recipies for n=3 and float values
55  *
56  */
57 
58 template < typename T >
59 bool solve_jacobi_3x3(
60  matrix< 3, 3, T >& a,
61  vector< 3, T >& d,
62  matrix< 3, 3, T >& v,
63  size_t& rotationCount )
64 {
65  identity( v );
66 
67  vector< 3, T > b, z;
68 
69  for ( size_t i = 0; i < 3; ++i )
70  {
71  b[i] = d[i] = a( i,i );
72  z[i] = 0.0;
73  }
74  T t, theta, s, c, tau;
75  size_t rot = 0;
76  for ( size_t i = 1; i <= 150; ++i )
77  {
78  T sm = 0.0;
79  for ( size_t ip = 0; ip < 2; ++ip ) // < n-1
80  {
81  for ( size_t iq = ip + 1; iq < 3; ++iq ) // < n
82  {
83  sm += fabs( a( iq, ip ) );
84  }
85  }
86  if ( sm == 0.0 )
87  {
88  rotationCount = rot;
89  return true;
90  }
91  T tresh = ( i < 4 ) ? 0.2 * sm / 9.0 : 0.0;
92 
93  for ( ssize_t ip = 0; ip < 2; ++ip ) // ip < n - 1
94  {
95  for ( ssize_t iq = ip + 1; iq < 3; ++iq )
96  {
97  T g = 100.0 * fabs( a( iq,ip ) );
98  // this has to be fabs( x ) + g == fabs( x ) and NOT
99  // g == 0.0 because of floating point evilness
100  // ( inaccuracies when comparing (anyfloat) to 0.0 )
101  if ( i > 4
102  && fabs( d[ip] ) + g == fabs( d[ip] )
103  && fabs( d[iq] ) + g == fabs( d[iq] )
104  )
105  {
106  a( iq, ip ) = 0.0;
107  }
108  else
109  {
110  if ( fabs( a( iq, iq ) ) > tresh )
111  {
112  T h = d[iq] - d[ip];
113  if ( fabs( h ) + g == fabs( h ) )
114  {
115  if ( h != 0.0 )
116  t = ( a( iq, ip ) ) / h;
117  else
118  t = 0.0;
119  }
120  else
121  {
122  if( a( iq, ip ) != 0.0 )
123  theta = 0.5 * h / ( a( iq, ip ) );
124  else
125  theta = 0.0;
126  t = 1.0 / ( fabs( theta ) + sqrt( 1.0 + theta * theta ) );
127  if ( theta < 0.0 )
128  t = -t;
129  }
130  c = 1.0 / sqrt( 1 + t * t );
131  s = t * c;
132  tau = s / ( 1.0 + c );
133  h = t * a( iq, ip );
134  z[ip] -= h;
135  z[iq] += h;
136  d[ip] -= h;
137  d[iq] += h;
138  a( iq, ip ) = 0.0;
139 
140  for ( ssize_t j = 0; j <= ip - 1; ++j )
141  {
142  g = a( ip, j );
143  h = a( iq, j );
144  a( ip, j ) = g - s * ( h + g * tau );
145  a( iq, j ) = h + s * ( g - h * tau );
146  }
147  for ( ssize_t j = ip + 1; j <= iq - 1; ++j )
148  {
149  g = a( j, ip );
150  h = a( iq, j );
151  a( j, ip ) = g - s * ( h + g * tau );
152  a( iq, j ) = h + s * ( g - h * tau );
153  }
154  for ( size_t j = iq + 1; j < 3; ++j )
155  {
156  g = a( j, ip );
157  h = a( j, iq );
158  a( j, ip ) = g - s * ( h + g * tau );
159  a( j, iq ) = h + s * ( g - h * tau );
160  }
161  for ( size_t j = 0; j < 3; ++j )
162  {
163  g = v( ip, j );
164  h = v( iq, j );
165  v( ip, j ) = g - s * ( h + g * tau );
166  v( iq, j ) = h + s * ( g - h * tau );
167  }
168  ++rot;
169  }
170  }
171  }
172  }
173 
174  for ( size_t ip = 0; ip < 3; ++ip )
175  {
176  b[ip] += z[ip];
177  d[ip] = b[ip];
178  z[ip] = 0.0;
179  }
180  }
181  return false;
182 
183 }
184 
185 } // namespace vmml
186 
187 #endif
188