2 * This program is free software: you can redistribute it and/or modify
3 * it under the terms of the GNU Lesser General Public License as
4 * published by the Free Software Foundation, either version 3 of the
5 * License, or (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 * @file EigenDecomposition.ih
19 * @author Jacques-Olivier Lachaud (\c jacques-olivier.lachaud@univ-savoie.fr )
20 * Laboratory of Mathematics (CNRS, UMR 5127), University of Savoie, France
24 * Implementation of inline methods defined in EigenDecomposition.h
26 * This file is part of the DGtal library.
30//////////////////////////////////////////////////////////////////////////////
32//////////////////////////////////////////////////////////////////////////////
34///////////////////////////////////////////////////////////////////////////////
35// IMPLEMENTATION of inline methods.
36///////////////////////////////////////////////////////////////////////////////
38///////////////////////////////////////////////////////////////////////////////
39// ----------------------- Standard services ------------------------------
41//-----------------------------------------------------------------------------
42template <DGtal::Dimension TN, typename TComponent, typename TMatrix>
44DGtal::EigenDecomposition<TN,TComponent,TMatrix>::
45tridiagonalize( Matrix& V, Vector& d, Vector& e )
47 for( Dimension j = 0; j < dimension; ++j )
48 d[ j ] = V ( dimensionMinusOne, j );
49 // Householder reduction to tridiagonal form.
50 for( Dimension i = dimensionMinusOne; i > 0 && i <= dimensionMinusOne; --i )
52 // Scale to avoid under/overflow.
53 Quantity scale = Quantity( 0.0 );
54 Quantity h = Quantity( 0.0 );
55 for( Dimension k = 0; k < i; ++k )
57 scale += Quantity( std::fabs( d[ k ] ));
60 if( scale == Quantity( 0.0 ))
64 for( Dimension j = 0; j < i; ++j )
66 d[ j ] = V(( i - 1 ), j );
67 V.setComponent ( i, j, Quantity( 0.0 ));
68 V.setComponent ( j, i, Quantity( 0.0 ));
73 // Generate Householder vector.
74 for ( Dimension k = 0; k < i; ++k )
80 Quantity f = d[ i - 1 ];
81 Quantity g = Quantity( std::sqrt( h ));
83 if ( f > Quantity( 0.0 ))
92 for ( Dimension j = 0; j < i; ++j)
94 e[ j ] = Quantity( 0.0 );
97 // Apply similarity transformation to remaining columns.
98 for ( Dimension j = 0; j < i; ++j )
101 V.setComponent ( j, i, f );
102 g = e[ j ] + V( j, j ) * f;
104 for ( Dimension k = j + 1; k <= i - 1; ++k )
106 g += V ( k, j ) * d[ k ];
107 e[ k ] += V ( k, j ) * f;
114 for ( Dimension j = 0; j < i; ++j )
117 f += e[ j ] * d[ j ];
120 double hh = f / ( h + h );
122 for ( Dimension j = 0; j < i; ++j )
124 e[ j ] -= hh * d[ j ];
127 for ( Dimension j = 0; j < i; ++j )
132 for ( Dimension k = j; k <= i - 1; ++k )
134 V.setComponent ( k, j, V ( k, j ) - ( f * e[ k ] + g * d[ k ] ));
137 d[ j ] = V( i - 1, j );
138 V.setComponent ( i, j, Quantity( 0.0 ));
144 // Accumulate transformations.
145 for ( Dimension i = 0; i < dimensionMinusOne; ++i )
147 V.setComponent ( dimensionMinusOne, i, V ( i, i ));
148 V.setComponent ( i, i, Quantity( 1.0 ));
149 Quantity h = d[ i + 1 ];
151 if ( h != Quantity( 0.0 ) )
153 for ( Dimension k = 0; k <= i; ++k )
155 d[ k ] = V ( k, i + 1 ) / h;
158 for ( Dimension j = 0; j <= i; ++j )
160 Quantity g = Quantity( 0.0 );
162 for ( Dimension k = 0; k <= i; ++k )
164 g += V ( k, i + 1 ) * V( k, j );
167 for ( Dimension k = 0; k <= i; ++k )
169 V.setComponent ( k, j, V ( k, j ) - ( g * d[ k ] ));
173 for ( Dimension k = 0; k <= i; ++k )
175 V.setComponent ( k, i + 1, Quantity( 0.0 ));
179 for ( Dimension j = 0; j < dimension; ++j )
181 d[ j ] = V ( dimensionMinusOne, j );
182 V.setComponent ( dimensionMinusOne, j, Quantity( 0.0 ));
185 V.setComponent ( dimensionMinusOne, dimensionMinusOne, Quantity( 1.0 ));
186 e[ 0 ] = Quantity( 0.0 );
189//-----------------------------------------------------------------------------
190template <DGtal::Dimension TN, typename TComponent, typename TMatrix>
192DGtal::EigenDecomposition<TN,TComponent,TMatrix>::
193decomposeQL( Matrix& V, Vector& d, Vector e )
195 for ( Dimension i = 1; i < dimension; ++i )
198 e[ dimensionMinusOne ] = 0.0;
200 Quantity f = Quantity( 0.0 );
201 Quantity tst1 = Quantity( 0.0 );
202 Quantity eps = Quantity( std::pow( 2.0, -52.0 ));
203 for( Dimension l = 0; l < dimension; ++l )
205 // Find small subdiagonal element
206 tst1 = Quantity( std::max( tst1, std::fabs ( d[ l ] ) + std::fabs( e[ l ] )));
208 while ( m < dimension )
210 if ( std::fabs ( e[ m ] ) <= eps * tst1 ) break;
214 // If m == l, d[l] is an eigenvalue,
215 // otherwise, iterate.
220 // Compute implicit shift
222 Quantity p = ( d[ l + 1 ] - g ) / ( Quantity( 2.0 ) * e[ l ] );
223 Quantity r = Quantity( std::sqrt ( p * p + Quantity( 1.0 ) * Quantity( 1.0 )));
225 d[ l ] = e[ l ] / ( p + r );
226 d[ l + 1 ] = e[ l ] * ( p + r );
227 Quantity dl1 = d[ l + 1 ];
228 Quantity h = g - d[ l ];
229 for( Dimension i = l + 2; i < dimension; ++i )
233 // Implicit QL transformation.
235 Quantity c = Quantity( 1.0 );
238 Quantity el1 = e[ l + 1 ];
239 Quantity s = Quantity( 0.0 );
240 Quantity s2 = Quantity( 0.0 );
241 for ( Dimension i = m - 1; i >= l && i <= m - 1; --i )
248 r = Quantity( std::sqrt ( p * p + e[ i ] * e[ i ] ));
252 p = c * d[ i ] - s * g;
253 d[ i + 1 ] = h + s * ( c * g + s * d[ i ] );
255 // Accumulate transformation.
256 for( Dimension k = 0; k < dimension; ++k )
259 V.setComponent ( k, i + 1, ( s * V ( k, i ) + c * h ));
260 V.setComponent ( k, i, ( c * V ( k, i ) - s * h ));
264 p = - s * s2 * c3 * el1 * e[ l ] / dl1;
267 // Check for convergence.
269 while ( std::fabs ( e[ l ] ) > eps * tst1 );
272 e[ l ] = Quantity( 0.0 );
274 // Sort eigenvalues and corresponding vectors.
275 for ( Dimension i = 0; i < dimensionMinusOne; ++i )
280 for ( Dimension j = i + 1; j < dimension; ++j )
292 for ( Dimension j = 0; j < dimension; ++j )
295 V.setComponent ( j, i, V ( j, k ));
296 V.setComponent ( j, k, p );
301//-----------------------------------------------------------------------------
302template <DGtal::Dimension TN, typename TComponent, typename TMatrix>
304DGtal::EigenDecomposition<TN,TComponent,TMatrix>::
305getEigenDecomposition( const Matrix& matrix, Matrix& eigenVectors, Vector& eigenValues )
307 Vector e; // Default constructor sets to zero vector;
308 eigenVectors = matrix; // copy matrix
309 eigenValues = e; // Sets to zero vector
310 tridiagonalize( eigenVectors, eigenValues, e );
311 decomposeQL( eigenVectors, eigenValues, e );
315///////////////////////////////////////////////////////////////////////////////