Changed the template argument in JacobiRotate and added method for sorting eigenvalues and eigenvectors (SortEigenvaluesAndEigenvectors)

This commit is contained in:
Paolo Cignoni 2006-07-24 07:26:47 +00:00
parent 7752f015eb
commit 68b176d276
1 changed files with 64 additions and 21 deletions

View File

@ -24,6 +24,9 @@
History
$Log: not supported by cvs2svn $
Revision 1.11 2006/05/25 09:35:55 cignoni
added missing internal prototype to Sort function
Revision 1.10 2006/05/17 09:26:35 cignoni
Added initial disclaimer
@ -41,11 +44,11 @@ namespace vcg
/*!
*
*/
template< typename TYPE >
static void JacobiRotate(Matrix44<TYPE> &A, TYPE s, TYPE tau, int i,int j,int k,int l)
template< typename MATRIX_TYPE >
static void JacobiRotate(MATRIX_TYPE &A, typename MATRIX_TYPE::ScalarType s, typename MATRIX_TYPE::ScalarType tau, int i,int j,int k,int l)
{
TYPE g=A[i][j];
TYPE h=A[k][l];
MATRIX_TYPE::ScalarType g=A[i][j];
MATRIX_TYPE::ScalarType h=A[k][l];
A[i][j]=g-s*(h+g*tau);
A[k][l]=h+s*(g-h*tau);
};
@ -57,17 +60,20 @@ namespace vcg
* \param v is a matrix whose columns contain, the normalized eigenvectors
* \param nrot returns the number of Jacobi rotations that were required.
*/
template <typename TYPE>
static void Jacobi(Matrix44<TYPE> &w, Point4<TYPE> &d, Matrix44<TYPE> &v, int &nrot)
template <typename MATRIX_TYPE, typename POINT_TYPE>
static void Jacobi(MATRIX_TYPE &w, POINT_TYPE &d, MATRIX_TYPE &v, int &nrot)
{
assert(w.RowsNumber()==w.ColumnsNumber());
int dimension = w.RowsNumber();
int j,iq,ip,i;
//assert(w.IsSymmetric());
TYPE tresh, theta, tau, t, sm, s, h, g, c;
Point4<TYPE> b, z;
MATRIX_TYPE::ScalarType tresh, theta, tau, t, sm, s, h, g, c;
POINT_TYPE b, z;
v.SetIdentity();
for (ip=0;ip<4;++ip) //Initialize b and d to the diagonal of a.
for (ip=0;ip<dimension;++ip) //Initialize b and d to the diagonal of a.
{
b[ip]=d[ip]=w[ip][ip];
z[ip]=0.0; //This vector will accumulate terms of the form tapq as in equation (11.1.14).
@ -76,9 +82,9 @@ namespace vcg
for (i=0;i<50;i++)
{
sm=0.0;
for (ip=0;ip<3;++ip) // Sum off diagonal elements
for (ip=0;ip<dimension-1;++ip) // Sum off diagonal elements
{
for (iq=ip+1;iq<4;++iq)
for (iq=ip+1;iq<dimension;++iq)
sm += fabs(w[ip][iq]);
}
if (sm == 0.0) //The normal return, which relies on quadratic convergence to machine underflow.
@ -86,12 +92,12 @@ namespace vcg
return;
}
if (i < 4)
tresh=0.2*sm/(4*4); //...on the first three sweeps.
tresh=0.2*sm/(dimension*dimension); //...on the first three sweeps.
else
tresh=0.0; //...thereafter.
for (ip=0;ip<4-1;++ip)
for (ip=0;ip<dimension-1;++ip)
{
for (iq=ip+1;iq<4;iq++)
for (iq=ip+1;iq<dimension;iq++)
{
g=100.0*fabs(w[ip][iq]);
//After four sweeps, skip the rotation if the off-diagonal element is small.
@ -118,22 +124,22 @@ namespace vcg
d[iq] += h;
w[ip][iq]=0.0;
for (j=0;j<=ip-1;j++) { //Case of rotations 1 <= j < p.
JacobiRotate<TYPE>(w,s,tau,j,ip,j,iq) ;
JacobiRotate<MATRIX_TYPE>(w,s,tau,j,ip,j,iq) ;
}
for (j=ip+1;j<=iq-1;j++) { //Case of rotations p < j < q.
JacobiRotate<TYPE>(w,s,tau,ip,j,j,iq);
JacobiRotate<MATRIX_TYPE>(w,s,tau,ip,j,j,iq);
}
for (j=iq+1;j<4;j++) { //Case of rotations q< j <= n.
JacobiRotate<TYPE>(w,s,tau,ip,j,iq,j);
for (j=iq+1;j<dimension;j++) { //Case of rotations q< j <= n.
JacobiRotate<MATRIX_TYPE>(w,s,tau,ip,j,iq,j);
}
for (j=0;j<4;j++) {
JacobiRotate<TYPE>(v,s,tau,j,ip,j,iq);
for (j=0;j<dimension;j++) {
JacobiRotate<MATRIX_TYPE>(v,s,tau,j,ip,j,iq);
}
++nrot;
}
}
}
for (ip=0;ip<4;ip++)
for (ip=0;ip<dimension;ip++)
{
b[ip] += z[ip];
d[ip]=b[ip]; //Update d with the sum of ta_pq ,
@ -142,6 +148,43 @@ namespace vcg
}
};
/*!
* Given the eigenvectors and the eigenvalues as output from JacobiRotate, sorts the eigenvalues
* into descending order, and rearranges the columns of v correspondinlgy.
/param eigenvalues
/param eigenvector
*/
template < typename MATRIX_TYPE, typename POINT_TYPE >
void SortEigenvaluesAndEigenvectors(POINT_TYPE &eigenvalues, MATRIX_TYPE &eigenvectors)
{
assert(eigenvectors.ColumnsNumber()==eigenvectors.RowsNumber());
int dimension = eigenvectors.ColumnsNumber();
int i, j, k;
float p;
for (i=0; i<dimension-1; i++)
{
p = eigenvalues[ k=i ];
for (j=i+1; j<dimension; j++)
if (eigenvalues[j] >= p)
p = eigenvalues[ k=j ];
if (k != i)
{
eigenvalues[k] = eigenvalues[i]; // i.e.
eigenvalues[i] = p; // swaps the value of the elements i-th and k-th
for (j=0; j<dimension; j++)
{
p = eigenvectors[j][i]; // i.e.
eigenvectors[j][i] = eigenvectors[j][k]; // swaps the eigenvectors stored in the
eigenvectors[j][k] = p; // i-th and the k-th column
}
}
}
};
// Computes (a^2 + b^2)^(1/2) without destructive underflow or overflow.
template <typename TYPE>